Postgres LIKE '...%' не использует индекс - PullRequest
0 голосов
/ 25 апреля 2020

У меня есть таблица, в которой я хочу искать по префиксу первичного ключа. Первичный ключ имеет значения, такие как 03.000221.1, 03.000221.2, 03.000221.3, et c. и я хочу получить все, что начинается с 03.000221..

Моей первой мыслью было отфильтровать с помощью LIKE '03.000221.%', думая, что Postgres будет достаточно умен, чтобы найти 03.000221. в индексе и выполнить дальность сканирования с этой точки. Но нет, при этом выполняется последовательное сканирование.

                                                   QUERY PLAN                                                    
-----------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..253626.34 rows=78 width=669)
   Workers Planned: 2
   ->  Parallel Seq Scan on ...  (cost=0.00..252618.54 rows=32 width=669)
         Filter: ((id ~~ '03.000221.%'::text)
 JIT:
   Functions: 2
   Options: Inlining false, Optimization false, Expressions true, Deforming true

Если я выполняю эквивалентную операцию, используя простой диапазон >= и <, например, id >= '03.000221.' and id < '03.000221.Z', он использует индекс:

                                                                 QUERY PLAN                                                                  
---------------------------------------------------------------------------------------------------------------------------------------------
 Index Scan using ... on ...  (cost=0.56..8.58 rows=1 width=669)
   Index Cond: ((id >= '03.000221.'::text) AND (id < '03.000221.Z'::text))

Но это грязнее, и мне кажется, что Postgres должен иметь возможность сделать вывод, что он может выполнить поиск в эквивалентном диапазоне индекса с помощью LIKE. Почему нет?

1 Ответ

2 голосов
/ 25 апреля 2020

PostgreSQL сделает это, если вы строите индекс с оператором text_pattern_ops или если вы используете сопоставление C.

Если вы используете какое-то другое случайное сопоставление, PostgreSQL не может многое из этого сделать. Обратите внимание на это в очень распространенном сопоставлении «en_US.utf8».

select * from (values ('03.000221.1'), ('03.0002212'), ('03.000221.3')) f(x) order by x;
      x      
-------------
 03.000221.1
 03.0002212
 03.000221.3

, что, естественно, приводит к неправильному ответу на ваш запрос:

select * from (values ('03.000221.1'), ('03.0002212'), ('03.000221.3')) f(id)
    where ((id >= '03.000221.'::text) AND (id < '03.000221.Z'::text))
     id      
-------------
 03.000221.1
 03.0002212
 03.000221.3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...