- 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.
inkanus-gray 05.02.2014 13:17 # +2
Рассмотрим варианты:
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).
И почему здесь нельзя использовать индекс?
bormand 05.02.2014 15:18 # 0
Дык он по обоим полям, и поэтому его можно поюзать только в случаях 2 и 3 ;)
inkanus-gray 07.02.2014 21:53 # 0
bormand 07.02.2014 22:01 # 0
Если это небольшой справочник или у этих полей офигенная селективность - то вполне хватает отдельного индекса на каждую такую колонку.
P.S. Я ни разу не DBA, так что ждем более авторитетных ответов ;)
bormand 07.02.2014 22:20 # +1
Ибо другое количество строк в таблицах, распределение значений в колонках или примерное количество строчек в выхлопе могут перевернуть план с ног на голову ;)
Например, тот же постгрес тупо забивает на индексы, если запрос возвращает бОльшую часть таблицы.
DBdev 08.02.2014 21:40 # +2
Как и все вменяемые СУБД.
anonimb84a2f6fd141 09.02.2014 06:35 # 0
bormand 09.02.2014 07:27 # +2
Ну не юзает их, т.к. если строк в выхлопе будет дохуя, то прямой скан таблички будет намного быстрее, чем куча рандомных чтений индекса и записей, на которые он ссылается.
> как он определяет сколько вернет запрос
На глаз :) СУБД собирает статистику по таблицам - сколько записей, какой разброс значений в полях и т.п. На основе этой статистики планировщик прикидывает сколько записей получится в ответе (можешь посмотреть в explain, там видно эту оценку). Тут же только порядок важен, на точное значение всем насрать.
DBdev 08.02.2014 21:40 # +1
99,9% случаев решает этот метод.
> P.S. Я ни разу не DBA, так что ждем более авторитетных ответов ;)
Вполне авторитетный ответ.
Bart 05.02.2014 13:23 # +9
(@userid!=null and @account=null) // Имею желание купить дом, но не имею возможности
(@userid=null and @account!=null)) // Имею возможность купить козу, но не имею желания
//Так выпьем же за то, чтобы
T.userid=@userid //наши желания всегда совпадали
T.account=@account // с нашими возможностями
3Doomer 05.02.2014 15:00 # 0
Надо нужных в отдельную таблицу выкинуть(и добавлять туда по мере регистрации новых), ибо каждый раз перебирать все записи - некомильфо.
архитектуропроблемы
bormand 05.02.2014 15:14 # +4
Это в какой же СУБД работает такая проверка на налл? Небось опять майкрософт решил выпендриться и пойти против системы? :)
DBdev 05.02.2014 18:09 # +1
99%, что просто запрос писал знаток SQL.
ЗЫЖ != это не МС, в МС <>
bormand 05.02.2014 18:15 # 0
DBdev 05.02.2014 18:28 # +1
В МС и != и <> работают. Это просто я постоянно <> юзаю. Так что может и МС.
Bart 05.02.2014 18:30 # 0
bormand 05.02.2014 18:47 # 0
Так что походу все-таки это m$.
Bart 05.02.2014 19:16 # 0
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.
bormand 06.02.2014 07:23 # +1
Я почему и спросил выше "Это в какой же СУБД работает такая проверка на налл?".
Поэтому предположение такое:
1) Это M$SQL, т.к. переменные с собачками
2) Автор кода тупо не знал, как правильно проверять на null
eth0 05.02.2014 17:14 # +2
bormand 05.02.2014 17:31 # +2
- у юзера может быть несколько счетов;
- один счет может принадлежать нескольким юзерам.
inkanus-gray 05.02.2014 17:34 # +3
1. Не нужно публиковать в Багминоте пароли от общих учёток.
2. Не нужно перелогиниваться, чтобы задействовать мультов.
eth0 05.02.2014 17:43 # +2
bormand 07.02.2014 21:19 # 0
eth0 08.02.2014 13:59 # 0
DBdev 05.02.2014 18:20 # +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))
....
А СУБД НЕ использует идексы из-за того, что у Вас в запросе переменные. Если подставить литералы, то индексы будут использоваться.
guest 07.02.2014 09:15 # +1
Так что "Разрешите пригласить Вас на танец, Сударь".
bormand 07.02.2014 09:44 # +3
Лолшто. Не найдет он их. Даже если из налл написать вместо корявых сравнений.
> А переписал бы он как вы предложили, то при обоих нулевых параметрах получил бы всю таблицу.
Согласен. Можно пофиксить ифом и выбросом исключения. Ибо нехуй передавать два налла (поди туда не знаю куда, принеси то не знаю что).
DBdev 07.02.2014 16:59 # +2
Да, в моём примере, если все параметры не переданы, то вернётся вся таблица.
В таких случаях просто в начале делается проверка на то, что они все пусты и делается ретурн.
> Так что "Разрешите пригласить Вас на танец, Сударь".
Разрешаю. Приглашайте.
bormand 07.02.2014 19:40 # 0
Что во многих случаях вполне логично. Например, если эти параметры юзаются как фильтры какого-то справочника...
eth0 07.02.2014 19:55 # +1
bormand 07.02.2014 20:32 # +1
Даже с фильтрами больше 40-50 записей во-первых не влезут в экран, а во-вторых юзер скорее всего даже не будет их смотреть, а тупо добавит еще фильтров, ибо лень ;)
P.S. А если юзеру приходится переключаться на вторую страничку - значит или это какой-то нештатный случай, ручная сверка, или же автор софта отъявленный садист, не умеющий в юзабилити.
DBdev 07.02.2014 20:50 # +2
Но ситуации бывают разные, и если фильтры применяются к справочной таблице, то может и все данные надо затянуть, на аппликейшн левел, например.
bormand 07.02.2014 21:16 # 0
Еще в студенческих и джуниорских работах поделках доставляют комбобоксы для выбора из справочников (каюсь, сам такой фигней страдал).
> Но ситуации бывают разные
Ключевая фраза ;)
eth0 08.02.2014 14:01 # 0
Никто не спорит, лимиты нужны. С другой стороны, всё опять же определяется задачей UI.
bormand 08.02.2014 15:00 # 0
Вот именно такие я и имел в виду ;) А там где 5-10 - да, комбобокс вполне подходит.
eth0 08.02.2014 19:42 # 0
Единственное, что приходит навскидку в голову - интеллектуальная система подбора, что-то типа "ваз 2101 2014-го года в полной комплектации".
bormand 08.02.2014 20:31 # 0
А если там дохрена вариантов, и никак не догадаться, что именно нужно писать - просто кнопка по которой показывается справочник с гридом и нормальными фильтрами.
eth0 09.02.2014 10:22 # 0
Vasiliy 11.02.2014 16:06 # +1