ускорение поиска по шаблону - PullRequest
10 голосов
/ 09 февраля 2012

У меня есть простая таблица в Postgres с более чем 8 миллионами строк.Интересующий столбец содержит короткие текстовые строки, обычно одно или несколько слов общей длиной менее 100 символов.Это установлено как 'изменение символа (100)'.Столбец индексируется.Простой поиск, как показано ниже, занимает> 3000 мс.

SELECT a, b, c FROM t WHERE a LIKE '?%'

Да, сейчас нужно просто найти строки, где "a" начинается с введенного текста.Я хочу довести скорость просмотра до 100 мс (появление мгновенно).Предложения?Мне кажется, что полнотекстовый поиск здесь не поможет, так как моя колонка текста слишком коротка, но я был бы рад попробовать, если это того стоит.

О, кстати, я также загрузил те же самые данные в mongodbи индексированный столбец «а».Загрузка данных в mongodb была удивительно быстрой (mongodb ++).И mongodb, и Postgres в значительной степени мгновенны при выполнении точных поисков.Но Postgres на самом деле светит, когда выполняет поиск по подстановочным знакам, как указано выше, последовательно занимая примерно 1/3 длины mongodb.Я был бы счастлив продолжить mongodb, если бы мог ускорить это, поскольку это только операция только для чтения.

Обновление: Сначала пара EXPLAIN ANALYZE выходов

EXPLAIN ANALYZE SELECT a, b, c FROM t WHERE a LIKE 'abcd%'

"Seq Scan on t  (cost=0.00..282075.55 rows=802 width=40) 
    (actual time=1220.132..1220.132 rows=0 loops=1)"
"  Filter: ((a)::text ~~ 'abcd%'::text)"
"Total runtime: 1220.153 ms"

Я на самом деле хочу сравнить Lower(a) с поисковым термином, длина которого не менее 4 символов, поэтому

EXPLAIN ANALYZE SELECT a, b, c FROM t WHERE Lower(a) LIKE 'abcd%'

"Seq Scan on t  (cost=0.00..302680.04 rows=40612 width=40) 
    (actual time=4.681..3321.387 rows=788 loops=1)"
"  Filter: (lower((a)::text) ~~ 'abcd%'::text)"
"Total runtime: 3321.504 ms"

Итак, я создал индекс

CREATE INDEX idx_t ON t USING btree (Lower(Substring(a, 1, 4) ));

"Seq Scan on t  (cost=0.00..302680.04 rows=40612 width=40) 
    (actual time=3243.841..3243.841 rows=0 loops=1)"
"  Filter: (lower((a)::text) = 'abcd%'::text)"
"Total runtime: 3243.860 ms"

Кажется,индекс используется только тогда, когда я ищу точное совпадение

EXPLAIN ANALYZE SELECT a, b, c FROM t WHERE a = 'abcd'

"Index Scan using idx_t on geonames  (cost=0.00..57.89 rows=13 width=40) 
    (actual time=40.831..40.923 rows=17 loops=1)"
"  Index Cond: ((ascii_name)::text = 'Abcd'::text)"
"Total runtime: 40.940 ms"

Нашел решение, внедрив индекс с varchar_pattern_ops, а теперь ищет еще более быстрые поиски .

Ответы [ 2 ]

7 голосов
/ 10 февраля 2012

Планировщик запросов PostgreSQL умный, но не AI. Чтобы сделать это, используйте индекс для выражения , используйте точно такую ​​же форму выражения в запросе.

С таким индексом:

CREATE INDEX t_a_lower_idx ON t (lower(substring(a, 1, 4)));

Или проще в PostgreSQL 9.1:

CREATE INDEX t_a_lower_idx ON t (lower(left(a, 4)));

Используйте этот запрос:

SELECT * FROM t WHERE lower(left(a, 4)) = 'abcd';

Что на 100% функционально эквивалентно:

SELECT * FROM t WHERE lower(a) LIKE 'abcd%'

Или:

SELECT * FROM t WHERE a ILIKE 'abcd%'

Но не :

SELECT * FROM t WHERE a LIKE 'abcd%'

Это функционально другой запрос , и вам нужен другой индекс:

CREATE INDEX t_a_idx ON t (substring(a, 1, 4));

Или проще с PostgreSQL 9.1:

CREATE INDEX t_a_idx ON t (left(a, 4));

И используйте этот запрос:

SELECT * FROM t WHERE left(a, 4) = 'abcd';

Слева привязанные условия поиска переменной длины

без учета регистра. Индекс:

Редактировать : Почти забыл: если вы запускаете свою БД с любым другим языковым стандартом, кроме 'C' по умолчанию, вам нужно явно указать класс оператора - text_pattern_ops в моем пример:

CREATE INDEX t_a_lower_idx
ON t (lower(left(a, <insert_max_length>)) text_pattern_ops);

Запрос:

SELECT * FROM t WHERE lower(left(a, <insert_max_length>)) ~~ 'abcdef%';

Может использовать индекс и почти так же быстро, как вариант с фиксированной длиной.

Вас может заинтересовать этот пост на dba.SE с более подробной информацией о сопоставлении с шаблоном , особенно с последней частью об операторах ~>=~ и ~<~.

.
0 голосов
/ 09 февраля 2012

Четко задокументировано, что поиск по регулярному выражению не использует индексы для различных реализаций. Единственный возможный способ использования индексов с регулярными выражениями ограничен поиском по префиксу, например *.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...