11.01.2008, 12:25 | #1 |
MCTS
|
LIKE VS EXISTS JOIN
Всем превед!
Представим следующую ситуацию: есть табличка LedgerTrans с большим количеством записей (порядка 500 тыс.). Соответственно нужно выбрать из нее только записи, у которых счет равен 10.100 и 10.200. Внимание - вопрос! Какой запрос отработает быстрее? 1. select LedgerTrans exist join param where LedgerTrans.AccountNum == param.AccountNum (param - табличка, в которой перечислены нужные счета, в нашем случае 10.100 и 10.200). 2. select LedgerTrans where LedgerTrans.AccountNum like "10.*" Последний раз редактировалось CDR; 11.01.2008 в 12:38. |
|
11.01.2008, 12:27 | #2 |
Участник
|
А если взять да попробовать?
|
|
11.01.2008, 12:28 | #3 |
Участник
|
А так
X++: select LedgerTrans where LedgerTrans.AccountNum >= "10." && LedgerTrans.AccountNum <= "10.Я" // или LedgerTrans.AccountNum < "10<соедующий символ после точки>" |
|
11.01.2008, 12:35 | #4 |
MCTS
|
|
|
11.01.2008, 12:35 | #5 |
Участник
|
Если по AccountNum есть индекс, то с точки зрения SQL - like будет меньше ресурсов потреблять чем join. И потом exist join не факт что будет 1 запросом работать на сервере.
|
|
11.01.2008, 12:39 | #6 |
Участник
|
Доп вопросы:
1. Какое число записей в LedgerTrans соответствуют условию ? 2. Какие индексы есть на таблице LedgerTrans ? 3. Таблица Param постоянная или временная ? 4. Какие индексы есть на таблице Param ? 5. Какое выравнивание у поля LedgerTrans.AccountNum, влево или вправо ? |
|
11.01.2008, 12:40 | #7 |
MCTS
|
Больше интересует скорость исполнения, а не потребляемые ресурсы. Что выполниться быстрее: построится join или просканируется like?
|
|
11.01.2008, 12:46 | #8 |
Участник
|
|
|
11.01.2008, 12:55 | #9 |
Участник
|
Цитата:
Сообщение от CDR
Всем превед!
Представим следующую ситуацию: есть табличка LedgerTrans с большим количеством записей (порядка 500 тыс.). Соответственно нужно выбрать из нее только записи, у которых счет равен 10.100 и 10.200. Внимание - вопрос! Какой запрос отработает быстрее? 1. select LedgerTrans exist join param where LedgerTrans.AccountNum == param.AccountNum (param - табличка, в которой перечислены нужные счета, в нашем случае 10.100 и 10.200). 2. select LedgerTrans where LedgerTrans.AccountNum like "10.*" |
|
11.01.2008, 12:59 | #10 |
MCTS
|
|
|
11.01.2008, 13:00 | #11 |
Участник
|
tourist, я полагаю теоретически вариант 2. быстрее, так как SQL в 1. варианте не знает, что можно обойтись index scan по AccountNum, и в 1 варианте сначала сделать tableScan по param, потом nestedLoop по всем записям и indexSсan по LedgerTranns
|
|
11.01.2008, 13:32 | #12 |
MCTS
|
Хм... Только что опробовал обе конструкции на тестовой табличке с количеством записей около 200 тыс. Результат поразил, однако...
Конструкция с exist join выигрывает в скорости более чем в 10 раз Ваши каменты по этому поводу? |
|
11.01.2008, 13:40 | #13 |
Участник
|
А планчики можно?
А мой вариант? |
|
11.01.2008, 13:55 | #14 |
Участник
|
Честно говоря, тоже думал, что второй будет работать быстрее.
Особенно учитывая, что у LedgerTrans есть индекс, где первым полем идет AccountNum. Планы бы действительно интересно было посмотреть. |
|
11.01.2008, 14:15 | #15 |
Модератор
|
Цитата:
Например, запрос в QA без фильтра на DataAreaId ну и опять же метания между Цитата:
в нашем случае 10.100 и 10.200)
Цитата:
where LedgerTrans.AccountNum like "10.*"
покажи (ничего, что я на ТЫ? ) запросы и планы
__________________
-ТСЯ или -ТЬСЯ ? |
|
11.01.2008, 14:25 | #16 |
Участник
|
Думаю, что Join быстрее при наличии индекса, так как с Like он не используется
|
|
11.01.2008, 14:39 | #17 |
Участник
|
select LedgerTrans where LedgerTrans.AccountNum >= "10."
&& LedgerTrans.AccountNum < "10/" |
|
11.01.2008, 14:39 | #18 |
Участник
|
|
|
11.01.2008, 14:44 | #19 |
MCTS
|
Условия и план проведенного мной теста:
1. Создаем тестовую табличку Trans из двух полей: Id и Name. 2. На табличке создаем неуникальный индекс по полю Id, который делаем кластерным. 3. Создаем джобик, который в цикле наполняет эту таблицу значениями. У меня был такой: внешний цикл i от 1 до 40 000, внутренний цикл j от 1 до 12. Во внутреннем цикле вставляются записи в табличку из пункта 1 (Id = strfmt('%1',j)). Джобик рекомендуется запускать на довольно мощном серваке, а то уснуть можно 4. Создаем табличку Params с одним полем Id, На табличке создаем уникальный индекс, который делаем Primary и кластерным. В табличку вводим значения "1", "10", "11", "12". 5. Пишем тестовый джоб. В моем случае было два select'а: select count(recId) from Trans exists join Params where Trans.Id == Params.Id; select count(recId) from Trans where Trans.Id like '1*'; Между select'ами смотрим время (я пользовался WinAPI::getTickCount() вместо timeNow(), дает более точное значение ). 6. Джобик запускаем пару раз, что б снизить влияние всякого там кэша. Затем можно поменять select'ы местами, для большей уверености 7. Результатами делимсо тут. У меня, как я уже писал, exists join "сделал" like более чем в 10 раз |
|
11.01.2008, 14:47 | #20 |
MCTS
|
|
|