- 1
- 2
- 3
- 4
- 5
- 6
SELECT ...
FROM users_account
....
WHERE
(T.userid=@userid or (@userid=null and @account!=null))
and (T.account=@account or (@userid!=null and @account=null))
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
−166
SELECT ...
FROM users_account
....
WHERE
(T.userid=@userid or (@userid=null and @account!=null))
and (T.account=@account or (@userid!=null and @account=null))
Есть табличка с юзерами и счетами на которых у юзеров есть игровая валюта.
Есть индекс по обоим этим полям (userid, account).
Каждый такой запрос сканирует весь индекс,а не делает по ней поиск, чем и грузит субд.
Но попытки оптимизировать запрос не увечались успехом,
т.к. я так и не понял что хотел сказать автор в своём условии where.
Рассмотрим варианты:
1. @userid=null and @account!=null
Тогда (@userid=!null and @account=null) автоматически не выполнено и во WHERE остаётся только T.account=@account.
2. @userid=!null and @account=null
Тогда (@userid=null and @account=!null) автоматически не выполнено и во WHERE остаётся только T.userid=@userid.
3. Оба условия не выполняются (@userid и @account обе не нули или обе нули).
Тогда во WHERE аж два условия: (T.userid=@userid) and (T.account=@account).
И почему здесь нельзя использовать индекс?
Дык он по обоим полям, и поэтому его можно поюзать только в случаях 2 и 3 ;)
Если это небольшой справочник или у этих полей офигенная селективность - то вполне хватает отдельного индекса на каждую такую колонку.
P.S. Я ни разу не DBA, так что ждем более авторитетных ответов ;)
Ибо другое количество строк в таблицах, распределение значений в колонках или примерное количество строчек в выхлопе могут перевернуть план с ног на голову ;)
Например, тот же постгрес тупо забивает на индексы, если запрос возвращает бОльшую часть таблицы.
Как и все вменяемые СУБД.
Ну не юзает их, т.к. если строк в выхлопе будет дохуя, то прямой скан таблички будет намного быстрее, чем куча рандомных чтений индекса и записей, на которые он ссылается.
> как он определяет сколько вернет запрос
На глаз :) СУБД собирает статистику по таблицам - сколько записей, какой разброс значений в полях и т.п. На основе этой статистики планировщик прикидывает сколько записей получится в ответе (можешь посмотреть в explain, там видно эту оценку). Тут же только порядок важен, на точное значение всем насрать.
99,9% случаев решает этот метод.
> P.S. Я ни разу не DBA, так что ждем более авторитетных ответов ;)
Вполне авторитетный ответ.
(@userid!=null and @account=null) // Имею желание купить дом, но не имею возможности
(@userid=null and @account!=null)) // Имею возможность купить козу, но не имею желания
//Так выпьем же за то, чтобы
T.userid=@userid //наши желания всегда совпадали
T.account=@account // с нашими возможностями
Надо нужных в отдельную таблицу выкинуть(и добавлять туда по мере регистрации новых), ибо каждый раз перебирать все записи - некомильфо.
архитектуропроблемы
Это в какой же СУБД работает такая проверка на налл? Небось опять майкрософт решил выпендриться и пойти против системы? :)
99%, что просто запрос писал знаток SQL.
ЗЫЖ != это не МС, в МС <>
В МС и != и <> работают. Это просто я постоянно <> юзаю. Так что может и МС.
Так что походу все-таки это m$.
To determine whether an expression is NULL, use IS NULL or IS NOT NULL instead of comparison operators (such as = or !=). Comparison operators return UNKNOWN when either or both arguments are NULL.
Я почему и спросил выше "Это в какой же СУБД работает такая проверка на налл?".
Поэтому предположение такое:
1) Это M$SQL, т.к. переменные с собачками
2) Автор кода тупо не знал, как правильно проверять на null
- у юзера может быть несколько счетов;
- один счет может принадлежать нескольким юзерам.
1. Не нужно публиковать в Багминоте пароли от общих учёток.
2. Не нужно перелогиниваться, чтобы задействовать мультов.
SELECT ...
FROM users_account
....
WHERE
(T.userid=@userid or @userid IS NULL)
and (T.account=@account or @account IS NULL)
Тайный смысл таковой - если параметр НЕ передался в хранимку (по-дефолту NULL), то этот фильтр игнорируется. Танцы с неравенством не нужны.
Если СУБД - МС, то можно форсировать использование индексов хинтами. Например:
SELECT ...
FROM users_account WITH (INDEX (myMegaIndex))
....
А СУБД НЕ использует идексы из-за того, что у Вас в запросе переменные. Если подставить литералы, то индексы будут использоваться.
Так что "Разрешите пригласить Вас на танец, Сударь".
Лолшто. Не найдет он их. Даже если из налл написать вместо корявых сравнений.
> А переписал бы он как вы предложили, то при обоих нулевых параметрах получил бы всю таблицу.
Согласен. Можно пофиксить ифом и выбросом исключения. Ибо нехуй передавать два налла (поди туда не знаю куда, принеси то не знаю что).
Да, в моём примере, если все параметры не переданы, то вернётся вся таблица.
В таких случаях просто в начале делается проверка на то, что они все пусты и делается ретурн.
> Так что "Разрешите пригласить Вас на танец, Сударь".
Разрешаю. Приглашайте.
Что во многих случаях вполне логично. Например, если эти параметры юзаются как фильтры какого-то справочника...
Даже с фильтрами больше 40-50 записей во-первых не влезут в экран, а во-вторых юзер скорее всего даже не будет их смотреть, а тупо добавит еще фильтров, ибо лень ;)
P.S. А если юзеру приходится переключаться на вторую страничку - значит или это какой-то нештатный случай, ручная сверка, или же автор софта отъявленный садист, не умеющий в юзабилити.
Но ситуации бывают разные, и если фильтры применяются к справочной таблице, то может и все данные надо затянуть, на аппликейшн левел, например.
Еще в студенческих и джуниорских работах поделках доставляют комбобоксы для выбора из справочников (каюсь, сам такой фигней страдал).
> Но ситуации бывают разные
Ключевая фраза ;)
Никто не спорит, лимиты нужны. С другой стороны, всё опять же определяется задачей UI.
Вот именно такие я и имел в виду ;) А там где 5-10 - да, комбобокс вполне подходит.
Единственное, что приходит навскидку в голову - интеллектуальная система подбора, что-то типа "ваз 2101 2014-го года в полной комплектации".
А если там дохрена вариантов, и никак не догадаться, что именно нужно писать - просто кнопка по которой показывается справочник с гридом и нормальными фильтрами.