not is distinct from & index

tadmin
Дата: 19.12.2014 14:06:39
Возможно ли использовать селективный индекс, имея два условия "not is distinct from "?

Условия задачи:
in_StorePlaceID is not null
coalesce(in_PhysicalArticleID,in_ContainerID) is not null
(in_PhysicalArticleID is null or in_ContainerID is null) = true

Запрос:
select SPI.StorePlaceItemID 
  from StorePlaceItems as SPI
    where SPI.StorePlaceID = in_StorePlaceID
      and not SPI.PhysicalArticleID is distinct from in_PhysicalArticleID
      and not SPI.ContainerID       is distinct from in_ContainerID


План:
Bitmap Heap Scan on storeplaceitems spi  (cost=1806.44..34794.78 rows=1 width=4) (actual time=51.394..51.736 rows=1 loops=1)
  Recheck Cond: ((storeplaceid)::integer = 332)
  Filter: ((NOT ((physicalarticleid)::integer IS DISTINCT FROM NULL::integer)) AND (NOT ((containerid)::integer IS DISTINCT FROM 3034602)))
  Rows Removed by Filter: 70831
  ->  Bitmap Index Scan on i_storeplaceitems_storeplace  (cost=0.00..1806.44 rows=76534 width=0) (actual time=15.217..15.217 rows=70834 loops=1)
        Index Cond: ((storeplaceid)::integer = 332)
Total runtime: 51.775 ms

Селективность по StorePlaceID низкая, но индексы по PhysicalArticleID, ContainerID разного рода никогда не используются.

Поскольку это фрагмент функции pl/pgsql, несложно проверить, какой из двух in_PhysicalArticleID, in_ContainerID not null, и применить явный запрос. В этом случае используется селективный индекс по StorePlaceID, PhysicalArticleID, ContainerID. План идеальный. Технически проблема решена.

Но есть ли способ получить оптимальный план, используя исходную конструкцию из двух not is distinct from?
Maxim Boguk
Дата: 19.12.2014 14:42:43
tadmin,

индексами в postgres покрываются только запросы вида поле operand значение
IS NOT DISTINCT не является операндом и ни при каких условиях индексами покрываться (на текущих версиях) не будет

PS: да это возможно сделать запатчив парсер/планировщик но на данный момент не сделано (я даже более менее понимаю как бы я делал - а именно ввел бы для всех типов специальный operand скажем ~=~ по смыслу эквивалетный IS NOT DISTINCT и подменял бы на этапе парсинга).

--Maxim Boguk
www.postgresql-consulting.ru
да, уж
Дата: 19.12.2014 15:02:36
Maxim Boguk
tadmin,

индексами в postgres покрываются только запросы вида поле operand значение
IS NOT DISTINCT не является операндом и ни при каких условиях индексами покрываться (на текущих версиях) не будет

PS: да это возможно сделать запатчив парсер/планировщик но на данный момент не сделано (я даже более менее понимаю как бы я делал - а именно ввел бы для всех типов специальный operand скажем ~=~ по смыслу эквивалетный IS NOT DISTINCT и подменял бы на этапе парсинга).

--Maxim Boguk
www.postgresql-consulting.ru

что крайне неудобно и непоследовательно ,когда есть индекс по списку (f1,....fn) и надо найти по точному совпадению ROW (т.е собственно по (f1,....fn) IS NOT DISTINCT FROM (v1,....vn)) ,а надо ручками раскладывать все пары в гробики
((f1=v1) OR ( f1 IS NULL AND v1 IS NULL) )
AND ......
AND (((fn=vn) OR ( fn IS NULL AND vn IS NULL) ))
tadmin
Дата: 19.12.2014 15:14:40
Maxim Boguk
IS NOT DISTINCT не является операндом и ни при каких условиях индексами покрываться (на текущих версиях) не будет

Вот оно что... Верно понимаю, что это единственный экземпляр скалярного "не оператора"?

Замена на if & явное "=" дало неплохое ускорение. Конструкция is distinct всегда казалась мне подозрительно изящной -)
Maxim Boguk
Дата: 19.12.2014 16:42:07
tadmin,

Кстати это есть в доке
"(At present, IS NOT DISTINCT FROM is handled much less efficiently than =, so don't do this unless you must. See Section 9.2 for more information on nulls and IS DISTINCT.)"
но почему то в pl/pgsql части (http://www.postgresql.org/docs/9.3/static/plpgsql-statements.html)

про скалярный не оператор в каком то смысле под это попадает field IS NOT NULL (который никогда не пойдет по индексу даже если NULL's составляют 99.9% значений) насколько я помню. При этом field IS NULL индексом покрывается.