A or null
От: MadHuman Россия  
Дата: 30.05.19 15:00
Оценка:
Всем привет!
Есть sql c
WHERE f1=1 or null
По f1 есть индекс. При этом план выполнения вместо поиска по индексу становится — TABLE SCAN (на самом деле SCAN TABLE .. USING COVERING INDEX)
Но если
WHERE f1=1
то используется INDEX SEEK.
Ну и в реальности на большой таблице, разница заметна, 1-й случай — секунда (или несколько, в зависимости от были ли в кэше данные), 2-й — 1мс (почти всегда).
База данных — sqlite.


Почему для A or null не используется поиск индексу? Ведь результаты для 1 и 2-го варианта одинаковы, я не вижу смысла использовать менее эффектиный план для 1-го варианта.
Это sqlite не додумывается? хотя верится с трудом тк вроде случай тривиальный и элеменировать несущественную константу не трудно..
Скорее всего есть какой-то нюанс который мне непонятен, но какой?
Как в других базах, такая же фигня?


PS sql генерится доволььно сложным образом и пока хотелось бы понять почему происходит вышеописанная хрень..
Re: A or null
От: Sharov Россия  
Дата: 30.05.19 15:10
Оценка:
Здравствуйте, MadHuman, Вы писали:

MH>Всем привет!

MH>Есть sql c
MH> WHERE f1=1 or null
MH>По f1 есть индекс. При этом план выполнения вместо поиска по индексу становится — TABLE SCAN (на самом деле SCAN TABLE .. USING COVERING INDEX)
MH>Но если
MH> WHERE f1=1
MH>то используется INDEX SEEK.
MH>Ну и в реальности на большой таблице, разница заметна, 1-й случай — секунда (или несколько, в зависимости от были ли в кэше данные), 2-й — 1мс (почти всегда).
MH>База данных — sqlite.


MH>Почему для A or null не используется поиск индексу? Ведь результаты для 1 и 2-го варианта одинаковы, я не вижу смысла использовать менее эффектиный план для 1-го варианта.


Вероятно, движок думает, что чтобы удовлетиворить условие null индекса не хватит, поэтому сканирует всю таблицу. Т.е. вероятно null записи в индекс не попадают.
Кодом людям нужно помогать!
Re[2]: A or null
От: MadHuman Россия  
Дата: 30.05.19 15:50
Оценка:
Здравствуйте, Sharov, Вы писали:

MH>Есть sql c

MH> WHERE f1=1 or null

MH>>Почему для A or null не используется поиск индексу? Ведь результаты для 1 и 2-го варианта одинаковы, я не вижу смысла использовать менее эффектиный план для 1-го варианта.


S>Вероятно, движок думает, что чтобы удовлетиворить условие null индекса не хватит, поэтому сканирует всю таблицу. Т.е. вероятно null записи в индекс не попадают.

это врядли, тк в данном случае в результат попадают только записи с не пустым значением в f1 (даже с конкретным = 1), и то что в индексе нет записей с null, не мешает его использовать для поиска записей с f1=1
то есть для движка не использовать индекс на основании того что в него не включены записи с null в f1, никак не является внятной мотивацией для такого его поведения.
Re[3]: A or null
От: Sharov Россия  
Дата: 30.05.19 16:17
Оценка:
Здравствуйте, MadHuman, Вы писали:

MH>Здравствуйте, Sharov, Вы писали:


MH>>Есть sql c

MH>> WHERE f1=1 or null

MH>>>Почему для A or null не используется поиск индексу? Ведь результаты для 1 и 2-го варианта одинаковы, я не вижу смысла использовать менее эффектиный план для 1-го варианта.


S>>Вероятно, движок думает, что чтобы удовлетиворить условие null индекса не хватит, поэтому сканирует всю таблицу. Т.е. вероятно null записи в индекс не попадают.

MH>это врядли, тк в данном случае в результат попадают только записи с не пустым значением в f1 (даже с конкретным = 1), и то что в индексе нет записей с null, не мешает его использовать для поиска записей с f1=1
MH>то есть для движка не использовать индекс на основании того что в него не включены записи с null в f1, никак не является внятной мотивацией для такого его поведения.

Так смысл использовать индекс, если для null все равно надо сканировать всю таблиуц? Тут боюсь, проблема не в движке, а в запросе, ибо как смысли в ентом or null
Кодом людям нужно помогать!
Re[4]: A or null
От: MadHuman Россия  
Дата: 30.05.19 16:38
Оценка:
Здравствуйте, Sharov, Вы писали:


S>Так смысл использовать индекс, если для null все равно надо сканировать всю таблиуц?

дак null тут по сути константа, для этого не надо ничего сканировать.

S> Тут боюсь, проблема не в движке, а в запросе, ибо как смысли в ентом or null

такой sql генерится автоматически в результате работы определённого нашего генератора, можно конечно логику генератора наворачивать, но пока хочется понять почему движок так себя ведет.
ведь добавка or null никак не меняет сути и результат отбора, и можно использовать индекс для более эффективного плана, но
движок почему-то не использует, вот и хочется понять — почему?


если всё таки копнуть почему у нас так генериться, то в самом начале был критерий типа A or B=Параметр1, где Параметр1 имеет пустое значение.
генератор содержит определённую логику оптимизации условий и B=null заменяет на константу null. поэтому и имеем в финале A or null.
Так лучше, тк константный null уже говорит что нечего из записи брать не надо, что вроде бы должно упрощать задачу оптимизатору движка БД.
заменять B=null на false нельзя, тк это может быть часть другого выражения типа (.... B=null ) is null, тогда результат будет неверный.
можно логику генерации и оптимизации условий наворачивать, но вроде же оптимизатор БД этим тоже и занимается, и должен заниматься лучше...
И вот надо понять, он тут не занимается потому что не научили?
или есть какая-то другая существенная причина?
Re: A or null
От: wildwind Россия  
Дата: 30.05.19 17:23
Оценка:
Здравствуйте, MadHuman, Вы писали:

MH> WHERE f1=1 or null


Точный текст приведи, пожалуйста.
Re[2]: A or null
От: MadHuman Россия  
Дата: 30.05.19 17:34
Оценка:
Здравствуйте, wildwind, Вы писали:

W>Здравствуйте, MadHuman, Вы писали:


MH>> WHERE f1=1 or null


W>Точный текст приведи, пожалуйста.


select count(*) from table1 where f1=1 or null
Re: A or null
От: Maniacal Россия  
Дата: 31.05.19 07:11
Оценка: 6 (1) +1
Здравствуйте, MadHuman, Вы писали:

MH>Почему для A or null не используется поиск индексу? Ведь результаты для 1 и 2-го варианта одинаковы, я не вижу смысла использовать менее эффектиный план для 1-го варианта.

MH>Скорее всего есть какой-то нюанс который мне непонятен, но какой?
MH>Как в других базах, такая же фигня?

При использовании в условии хотя бы одного OR всегда происходит TABLE SCAN
Нужно OR заменить на
WHERE coalesce(f1,1)=1
Re: A or null
От: Ops Россия  
Дата: 31.05.19 09:28
Оценка:
Здравствуйте, MadHuman, Вы писали:

MH> WHERE f1=1 or null


А это точно то, чего ты хочешь? М.б. where f1 = 1 or f1 is null?
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[2]: A or null
От: MadHuman Россия  
Дата: 31.05.19 09:46
Оценка:
Здравствуйте, Ops, Вы писали:

Ops>Здравствуйте, MadHuman, Вы писали:


MH>> WHERE f1=1 or null


Ops>А это точно то, чего ты хочешь?

Да, точно

Ops>М.б. where f1 = 1 or f1 is null?

Нет, именно where f1 = 1 or null
sql генерится автоматически, просто в определённом случае получается такой, и с точки зрения финального результата он валиден.
Но план выполнения, его не очень хорош (индекс не используется), что печально.
Раз sql валиден, то нехотелось бы лезть в логику генерации, полагал что оптимизатор движка БД сделает своё дело.

Я сначала думал что есть какой-то нюанс именно с null, но where f1 = 1 or 0 (где 0 — это по сути false, и можно сократить всё выражение до f1=1)
также имеет такую же проблему (план выполнения не использует индекс). Что говорит о том, что видимо всё таки оптимизатор не обучен таким простым оптимизациям.
Что тоже странно, ведь оптима тривиальная.
Re[3]: A or null
От: Maniacal Россия  
Дата: 31.05.19 09:51
Оценка:
Здравствуйте, MadHuman, Вы писали:

Ops>>А это точно то, чего ты хочешь?

MH>Да, точно

Ops>>М.б. where f1 = 1 or f1 is null?

MH>Нет, именно where f1 = 1 or null

Орнул с "OR null".
Эта часть условия всегда FALSE. Наличие OR + константа приводит к тому, что индекс использоваться не будет. Похоже на ошибку.
Отредактировано 31.05.2019 14:30 Maniacal . Предыдущая версия . Еще …
Отредактировано 31.05.2019 9:52 Maniacal . Предыдущая версия .
Re[2]: A or null
От: MozgC США http://nightcoder.livejournal.com
Дата: 31.05.19 13:55
Оценка: +1
Здравствуйте, Maniacal, Вы писали:

M>При использовании в условии хотя бы одного OR всегда происходит TABLE SCAN


Это неправда.
Отредактировано 31.05.2019 13:59 MozgC . Предыдущая версия .
Re[3]: A or null
От: Maniacal Россия  
Дата: 31.05.19 14:29
Оценка:
Здравствуйте, MozgC, Вы писали:

MC>Здравствуйте, Maniacal, Вы писали:


M>>При использовании в условии хотя бы одного OR всегда происходит TABLE SCAN


MC>Это неправда.

MC>Image: index.png
Ну, давно я на оракле не оптимизировал запросы. Возможно это когда скан по двум таблицам и между условиями для двух таблиц используется OR. Может, это особенность Oracle. Может, зависит от того, сколько полей в индексе.
Re[4]: A or null
От: wildwind Россия  
Дата: 25.05.19 12:06
Оценка:
Здравствуйте, Maniacal, Вы писали:

M>Ну, давно я на оракле не оптимизировал запросы. Возможно это когда скан по двум таблицам и между условиями для двух таблиц используется OR. Может, это особенность Oracle. Может, зависит от того, сколько полей в индексе.


Ораклоиду везде Оракл мерещится. У MozgC на картинке MSSQL. А у ТС вообще SQLite.

Кстати, ЕМНИП для Оракла X OR NULL всегда NULL, и запрос ТС будет всегда возвращать 0 строк.
Re[3]: A or null
От: wildwind Россия  
Дата: 25.05.19 12:07
Оценка:
Здравствуйте, MadHuman, Вы писали:

MH>Я сначала думал что есть какой-то нюанс именно с null, но where f1 = 1 or 0 (где 0 — это по сути false, и можно сократить всё выражение до f1=1)


Я как раз хотел порпросить проверить этот случай.

MH>также имеет такую же проблему (план выполнения не использует индекс). Что говорит о том, что видимо всё таки оптимизатор не обучен таким простым оптимизациям.


Похоже на баг. Напиши разработчикам.
Re: A or null
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.06.19 07:35
Оценка:
Здравствуйте, MadHuman, Вы писали:
MH>Почему для A or null не используется поиск индексу? Ведь результаты для 1 и 2-го варианта одинаковы, я не вижу смысла использовать менее эффектиный план для 1-го варианта.
Похоже на баг.
https://www.sqlite.org/optoverview.html#or_opt
Там вроде как каждый из термов под OR должен анализироваться, и оптимизируется
 rowid IN (SELECT rowid FROM table1 WHERE f1=1 
            UNION SELECT rowid FROM table1 WHERE null)
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: A or null
От: TMU_1  
Дата: 04.06.19 19:55
Оценка:
MH>Всем привет!
MH>Есть sql c
MH> WHERE f1=1 or null


От меня ускользает смысл этой конструкции. В части or null.
Re[2]: A or null
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.06.19 04:27
Оценка: +1
Здравствуйте, TMU_1, Вы писали:

TMU>От меня ускользает смысл этой конструкции. В части or null.

В некоторых диалектах bool-константу unknown называют null.
Не во всех диалектах можно написать её явно; можно получить её в результате вычисления выражения. Например, вот так:
select count(*) from table1 where f1=1 or 1 = null

Там явно какой-то генератор SQL попытался выполнить оптимизацию, свернув константное выражение в его результат. Это, вообще говоря, разумно, т.к. большинство СУБД не задуряются с микрооптимизациями самих выражений.
Считается, что эту работу надо проводить до того, как дёргать СУБД своими запросами. Вот оптимизации, зависящие от данных — это уже к СУБД (ну там, выкинуть выражение, которое заведомо совпадает с верифицированным check constraint).
Получается, что генератору SQL надо быть ещё умнее, и сворачивать A or null в A
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: A or null
От: MadHuman Россия  
Дата: 06.06.19 19:04
Оценка:
Здравствуйте, Sinclair, Вы писали:


S>Получается, что генератору SQL надо быть ещё умнее, и сворачивать A or null в A

Всё так, но была мысль, что эту работу сделает оптимизатор движка БД, но получается не делает.
Придётся заморочиться, чтоб в генераторе SQL её сделать, хотя уже заморочились и сделали
Re[2]: A or null
От: hlt Россия  
Дата: 19.06.19 06:17
Оценка:
M>Нужно OR заменить на
M>
M>WHERE coalesce(f1,1)=1
M>

В этом случае индекс по f1 тоже работать не будет, из-за функции.
Нужен будет индекс по coalesce(f1,1), если такое позволяет субд топикстартера.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.