Postgres SQL - странная проблема с производительностью в select - PullRequest
0 голосов
/ 24 сентября 2019

У меня есть запрос (упрощенная версия):

WITH temp AS (SELECT id, foo(id) AS foo FROM test)
SELECT id FROM temp WHERE foo = 4;

foo(id) - это функция, которая возвращает 0, 2 или 4 (только эти значения)

Выше запроса с ... WHERE foo = 4 принимаетминут, но удивительно, когда я перехожу на ... WHERE foo != 0 AND foo != 2 производительность запроса составляет миллисекунды.

То же самое, если я делаю ... WHERE foo > 2 - тоже очень быстро.

Я проверил план выполнения, но не вижулюбые различия.

Очень удивлен этим ... может кто-нибудь объяснить мне, почему?

1 Ответ

1 голос
/ 25 сентября 2019

Предполагая, что функция foo() не может быть встроенной, Postgres не знает, что она может вернуть, поэтому он должен предположить, что любое число одинаково распространено.

Предикат foo = 4 говорит Postgres ожидатьчто рядом с отсутствующей строкой будет соответствовать критериям.

Предикат foo != 0 AND foo != 2, OTOH, сообщает Postgres ожидать, что почти все строки соответствуют требованиям.С foo > 2 это по-прежнему примерно половина всех строк.

Это обычно приводит к различным планам запросов, и первый кажется плохо работающим, в то время как другие, кажется, работают хорошо.

Детали скрыты отсутствующей информацией.Но в этом суть.

Если функция IMMUTABLE, вы можете создать индекс выражения на foo(foo(id)).Этот индекс, вероятно, сам по себе бесполезен, если предположить, что 3 возможных значения распределены равномерно.( Может быть сканирование только по индексу для многоколоночного индекса foo(foo(id), id) поможет, если функция дорогая и объявлена ​​как таковая.) Но это заставляет Postgres собирать дополнительную статистику, которая сообщит планировщику запросов, чего ожидатьиз функции.Связанный:

...