Pull to refresh
0
0
Send message

Был не так давно на их собесе в качестве Oracle-разработчика. Хочу отметить, что особо глубокие вещи они не спрашивали, а те вещи, на которые я недостаточно хорошо ответил - по сути сам виноват, что забыл/недостаточно хорошо понял ранее. С другой стороны, даже такие не шибко глубокие вещи довольно редко нужны на практике, ибо практика обычно состоит в реализации бизнес-логики, а не вот этой вот постоянной предельной оптимизации и знании того, какими тремя путями может быть исполнен hash join в зависимости от кол-ва доступной памяти. Хотя на самом деле засыпался на простейшей задаче sql, сам не понял почему, то ли от волнения, то ли от того, что уже был глубокий вечер. Сидел тупил, после собеса сразу озарило, как это просто. Бывает. И вроде там не предполагалось еще по алгоритмам каким-то гонять.

Уверен на 95%, что Ваша ненависть скорее от незнания предмета, чем от ошибок оптимизатора Oracle:
1) В грамотно спроектированной и написанной БД (где разработчик понимает, как 3-я нормальная форма влияет на CBO) разработчику должно быть плевать (по большому счету) на конкретный cost конкретного запроса - и не плевать на реально узкие места или проблемы в производительности.
2) Если узкое место выявлено, на cost все равно плевать - ибо это во многом производная от cardinality, и если у вас на каком-то шаге в плане запроса неверная оценка в cardinality - надо разбираться, почему. Наложили ли вы все constraint, особенноо not null? Не используете ли в качестве заменителя null какое-нибудь 01.01.2999? Что со статистикой? Рассматривали ли добавление гистограмм?
3) Хинты - это своего рода костыли, которые тяжело поддерживать, и их обильное применение означает попытку лечить симптомы и заметать реальные проблемы под ковер. В хорошем коде хинты используются в исключительных случаях, а если тут и там разбросаны use_nl/use_hash (и мы не говорим про версии oracle ниже 10) - что-то в этой бд явно не так.

Вообще, судя по моим наблюдениям, разрабатывать БД (под Oracle, за остальные СУБД говорить не буду) должен как минимум специалист уровня Senior, если вы не хотите спустя какое-то время заниматься рефакторингом бд. Впрочем, даже такой подход ничего не гарантирует, поскольку, похоже, для oracle-senior нынче достаточно иметь опыт работы с секционированием, знать несколько хинтов, модель блокирования, ну и всякого прочего по мелочи. А потом оказывается, что на полях таблиц нет ограничений, а поле boolean-вида эмулируют как number(1). И это что касается именно Oracle-разработчиков... чем заканчивается то, когда бд под Oracle занимаются FullStack-и, даже говорить не хочу. Это, внезапно, не просто "знать, что есть таблицы-индексы и как они работают", а много больше...

Потом функция стала возвращать не 4 параметра, а 5 - и всё сломалось

В python такое считается нормальным? Ну, в смысле, когда кто-то меняет api функции и при этом не просматривает все места, откуда она вызывается? Дескать, не мои проблемы? :) При работе с компилируемым ЯП я бы только рад был, если бы такое ломалось и уже на этапе компиляции валилось с ошибкой.

Или при вызове функции программист их неправильно сосчитал. Или, чтобы не ошибиться с подсчетом, скопипастил правильный вызов, но не до конца исправил

А вот это уже манипулятивные аргументы :) Потому что это вообще здесь не при чем. Программист может ошибиться в чем угодно и где угодно. Чтобы не ошибаться при копипасте, надо не копипастить. А чтобы не ошибаться в написании кода, надо его не писать. Приведу пример из мира баз данных:

можно писать везде

select * from tbl

вместо

select fld_1, fld_2, ..., fld_n from tbl

дескать, если еще одно поле добавится, его не надо прописывать лиший раз. Но это может не только негативно сказаться на производительности, но и по сути означает потерю контроля над кодом. В этом месте нужно только эти поля, в этом - только вот эти. Читая везде все скопом сразу - по сути создается помойка, где непонятно, что именно нам нужно, ради мимолетного удобства программиста (не нужен копи-паст имени поля в те места, где оно нужно). Возможность ошибиться исключается, но возможностей ошибиться вообще бесконечно много, чтобы ради этого поступать в ущерб другим, важным областям (читабельность, производительность, контролируемость кода разработчиком, контроль зависимости объектов).

Имхо, второй вариант несёт меньше нагрузки.

Почему-то мое имхо с точностью до наоборот :)

Один из важнейших принципов читаемости, который я вывел за много лет кодинга (на pl/sql) - чтение кода должно вызывать как можно меньше вопросов. Вот я читаю первый вариант

roll, pitch, yaw, speed = get_many_params(object)

И тут нет особых вопросов. Также здесь соответствие принципу

Легко читать > Самодокументация > Названия переменных

Если меня вдруг заинтересует, где именно используется roll, и как именно - я либо воспользуюсь поиском, либо выделю слово, чтобы редактор его подсветил во всех остальных местах. Учитывая то, что функции у нас не километровые (в соответствии с другими вышеоговоренными принципами), проблем с этим нет.

Читая же

_, pitch, _, speed = get_many_params(object)

У меня сразу в голове возникают вопросы - а что именно скрывается за этими "_" - и будьте уверены, я пойду ковырять этот get_many_params в попытке это понять. А потом изменится алгоритм, бизнес-процессы, понадобится мне тот же roll, и придется после полугода забытья опять ковырять get_many_params, чтобы понять, где именно этот roll возвращается. В случае же первого варианта я сразу воспользуюсь этим roll. Здесь также нарушается принцип понятных имен. То есть принцип понятных имен входит в конфликт с принципом "неиспользуемое называем "_" ".

Исходя из всего вышесказанного, я бы предпочел сразу явно видеть, что к чему. Мне претит мысль, что из-за дизайна вызываемых функций надо вмешиваться в имена объектов вызывающих функций - это какое-то нарушение независимости получается.

Насчет стандартов ничего не могу сказать, ибо не специалист в python. Поэтому сужу с точки зрения "в целом", используя опыт кодинга на pl/sql :)

Отличная статья; во многом советы универсальны и не зависят от языка программирования. Не являясь специалистом Python (и поэтому буду стараться писать в общих терминах), все же отмечу моменты, с которыми не согласен:

1) Redundant else - нарушается блочная структура. Есть старое доброе правило - один вход, один выход. Вполне допуская оправданность конструкций вида:

if check_1: return
if check_2: return
...
main code

отмечу, что при такой структуре идет разрушение кода функции как одного блока, который можно во что-нибудь обернуть. Нередко встречал ситуации, когда в начале нужно вызвать какой-нибудь обработчик (логирование?) и в конце тоже нужно вызвать какой-нибудь обработчик (профилирование?). Оптимальным здесь считаю goto в конец, сразу перед return. Здесь можно возразить, что тогда следует написать функцию-обертку, но все же, все же... вариант с goto более "модульный" какой-то, что ли.

2) "Заменяйте ненужные переменные на underscore " - не понял смысл этого. Потом логика изменится, понадобится сослаться на эту переменную цикла, и придется изменить с "_" на "i"? Идея менять имя чего-то только потому, что оно вдруг понадобилось, выглядит довольно странной.

Но по большому счету, это мелочи.

Information

Rating
Does not participate
Registered
Activity