Влияние производительности запроса LIKE при работе с подмножеством полной таблицы - PullRequest
4 голосов
/ 22 марта 2012

Я ценю, что LIKE-запросы медленные, так как не могут быть проиндексированы.Тем не менее, мне любопытно, что производительность может снизиться в такой ситуации:

Скажем, у меня есть таблица типа:

user_id  |  message 
-------------------
   1     |  foo bar baz
   1     |  bar buz qux
   .     .      .
   .     .      .
   2     |  bux bar foo
   2     |  bar

, где я скажу 1 миллион строк, но 10 000 пользователей,у каждого пользователя около 100 сообщений.

Очевидно, что поиск вроде:

SELECT * FROM table WHERE message like '%ar%';

будет очень медленным.Однако в моем приложении я бы только искал сообщения пользователя:

SELECT * FROM table WHERE message like '%ar%' AND user_id = 2;

, где будет индексирован столбец user_id.

Прав ли я, полагая, что в таком сценарии,Postgres будет выполнять медленный LIKE-запрос только для пользователей ~ 100 строк после использования индексированного столбца user_id, а не полной таблицы - таким образом, ограничивая мое снижение производительности?

А также, что такой запрос не будет 'становится значительно медленнее с 10 или 100 миллионами пользователей, если у одного пользователя было всего ~ 100 сообщений?

Ответы [ 2 ]

8 голосов
/ 22 марта 2012

@ MatBailie уже снял ваш основной вопрос. Я хочу ответить на ваше утверждение:

Я ценю, что LIKE-запросы медленные, так как не могут быть проиндексированы.

Это не совсем так.

Во-первых , и это было верно в течение длительного времени, левые привязанные шаблоны могут использовать индекс. Это работает для регулярных выражений (~), а также LIKE (~~) и SIMILAR TO. Недавно я написал подробный обзор по этому вопросу на dba.SE:

.

Это может не сработать, потому что шаблоны в вашем вопросе не привязаны . Если бы они были, вы могли бы получить оптимизированную производительность с многоколоночным индексом , который использует класс оператора текстового шаблона text_pattern_ops для столбца message, например:

CREATE INDEX tbl_user_id_message_idx ON tbl (user_id, message text_pattern_ops);

Для запросов типа:

SELECT *
FROM   tbl
WHERE  user_id = 2
AND    message ~~ 'bar%'; -- left anchored LIKE

Во-вторых , так как в PostgreSQL 9.1 вы можете использовать расширение pg_trgm и создавать с его помощью индекс GIST или GIN, который всех шаблонов можно использовать. Некоторые ограничения применяются. Ведение такого индекса обходится дороже, поэтому оно наиболее полезно для таблиц только для чтения или редко записываемых таблиц. Детали:

У Depesz есть учебное пособие .

3 голосов
/ 22 марта 2012

Оптимизатор определяет многие вещи при компиляции SQL в план.

Одним из них является то, как фильтровать данные (с поиском по индексу и т. Д.) Перед применением других условий для каждой строки.

В вашем случае, если у вас есть подходящий индекс, LIKE будет применяться к записям только после выполнения этой фильтрации.

Чтобы понять это немного, получите план, созданный по вашему запросу.Вы должны увидеть, где индексы используются для поднабора / фильтрации данных, а затем - отдельный шаг, применяя условие LIKE.

...