2013-11-28 3 views
3

мне нужно создать процедуру с необязательными аргументами и использовать их, только если они не равны нулюДополнительные условия в запросе PostGreSQL

Мой текущий запрос выглядит следующим образом:

SELECT * FROM sth WHERE 
    (arg1 IS NULL OR sth.c1 = arg1) AND 
    (arg2 IS NULL OR sth.c2 = arg2) AND 
    (arg3 IS NULL OR sth.c3 > arg3) AND 
    (arg4 IS NULL OR sth.c4 < arg4) 

Я думаю так, чтобы он выглядел лучше/короче. Мой первый выстрел:

SELECT * FROM sth WHERE 
    COALESCE(sth.c1 = arg1, 't') AND 
    COALESCE(sth.c2 = arg2, 't') AND 
    COALESCE(sth.c3 > arg3, 't') AND 
    COALESCE(sth.c4 < arg4, 't'); 

, но я не уверен, если это выглядит лучше. Знаете ли вы какие-нибудь полезные приемы для этого?

+0

'' что-то = something'' либо '' true'' или ' 'false'', а не NULL – nrathaus

+2

@nrathaus:' anything = NULL' is null – Adassko

+1

Первая форма, вероятно, понятна и позволяет оптимизатору полностью вырезать выражения, доказав, что другая сторона 'OR' всегда истинна. Хотя планировщик может доказать, что '[anything] = NULL' всегда' NULL' тоже; Я не проверял; вы должны быть в состоянии сказать в 'explain' output. –

ответ

3

Держите это так, как есть. Использование coalesce не позволит планировщику запросов правильно выполнять свою работу, и в итоге вы получите планы сосать запросов.

Best я знаю, следующие выражения будут использовать индекс ВТКЕЯ:

  • col = 'val'
  • col is null

Следующие выражения не будут использовать индекс ВТКЕЯ:

  • col is [not] 'val'
  • (col = 'val') is [not] <true | false | null>
  • col is [not] distinct from 'val'
  • coalesce(col, 'val') = 'val'
  • coalesce(col = 'val', <true | false | null>)
+0

как насчет моего обновленного запроса? Будет ли планировщик запросов работать в этом случае? – Adassko

+0

Насколько я знаю, ваш первый - это единственный, который он попытается оптимизировать. Тот, который показал @Adassko, может выглядеть немного лучше, но использование оператора IS немного похоже на использование COALESCE: планировщик обычно дает сканирование seq. С исходным запросом он должен, по крайней мере, выполнить сканирование растрового индекса, и, скорее всего, он будет фактически подготовлен по-разному (и, как и в упрощенном виде) в зависимости от вашего входного параметра. –

+0

, но не является оператором 'IS', также используемым в первом запросе? – Adassko

1

Хорошо, я думаю, что этот запрос является лучшей идеей для этой цели

SELECT * FROM sth WHERE 
    NOT (sth.c1 = arg1) IS FALSE AND 
    NOT (sth.c2 = arg2) IS FALSE AND 
    NOT (sth.c3 > arg3) IS FALSE AND 
    NOT (sth.c4 < arg4) IS FALSE; 

он не использует какие-либо функции, так планировщик запросов должен работать нормально просто как и раньше

он просто использует простые выражения, где:

1. 
true = true // true 
true = false // false 
true = null // null 

2. 
false is false // true 
true is false // false 
null is false // false 

3. 
not true // false 
not false // true 

так будет возвращать true если выражение true ИЛИ null

+1

В PG 9.3 «объясните анализ select * из теста, где not (id = 5) является false' => seq scan + filter. 'объяснять анализ select * из теста, где id = 5 или 5 - это null' => индексное сканирование. –

Смежные вопросы