2017-02-19 4 views
0

Итак, у меня есть таблица, которая выглядит как:Почему Postgres отказывается использовать составной индекс в некоторых настройках?

        Table "public.rule_traffic" 
      Column  | Type |      Modifiers 
    id    | bigint | not null default nextval('rule_traffic_seq'::regclass) 
    device_id   | integer | not null 
    version_id  | integer | not null 
    policy_name  | text | 
    rule_uid   | uuid | not null 
    traffic_hash_code | bigint | not null 
    action   | integer | 

наряду с этими показателями:

"rule_traffic_pkey" PRIMARY KEY, btree (id) 
"unique_device_id_version_id_policy_name_uid_in_rule_traffic" UNIQUE, btree (device_id, version_id, policy_name, rule_uid) 

при запуске тестового запроса на моей установке (и многих других), это выглядит как «м на самом деле с использованием определенного индекса unique_device_id_version_id_policy_name_uid_in_rule_traffic:

                   QUERY PLAN 
HashAggregate (cost=8.29..8.30 rows=1 width=56) (actual time=1.563..1.563 rows=0 loops=1) 
-> Index Scan using unique_device_id_version_id_policy_name_uid_in_rule_traffic on rule_traffic this_ (cost=0.00..8.28 rows=1 width=56) (actual time=1.558..1.558 rows=0 loops=1) 
    Index Cond: ((device_id = 11) AND (policy_name IS NULL)) 
    Filter: ((rule_uid = 'f6c0dc29-e741-4f9a-adf1-f11d18768af3'::uuid) OR (rule_uid = 'c1a12087-2d85-4e44-a115-f9cad7ec915e'::uuid)) 
Total runtime: 1.704 ms 

но есть установка с совершенно другим планом запроса (последовательность СБНА ап):

                    QUERY PLAN 
HashAggregate (cost=150538.23..150538.25 rows=2 width=56) (actual time=2403.600..2403.601 rows=2 loops=1) 
-> Seq Scan on rule_traffic this_ (cost=0.00..150538.20 rows=4 width=56) (actual time=2354.481..2403.573 rows=2 loops=1) 
    Filter: ((policy_name IS NULL) AND (device_id = 11) AND ((rule_uid = 'f6c0dc29-e741-4f9a-adf1-f11d18768af3'::uuid) OR (rule_uid = 'c1a12087-2d85-4e44-a115-f9cad7ec915e'::uuid))) 
Total runtime: 2403.661 ms 

Я попытался запустить VACUUM ПОЛНЫЙ \ ПРОАНАЛИЗИРУЙТЕ на столе без каких-либо результатов.

Кто-нибудь есть идеи, почему postgres решает не использовать составной индекс?

UPDATE 1:

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

securetrack=# explain analyze select max(this_.id) as y0_, this_.rule_uid as y1_, this_.policy_name as y2_ from rule_traffic this_ where this_.device_id=11 and ((this_.rule_uid='f6c0dc29-e741-4f9a-adf1-f11d18768af3' and this_.policy_name is null) OR (this_.rule_uid = 'c1a12087-2d85-4e44-a115-f9cad7ec915e' and this_.policy_name is null)) group by this_.rule_uid, this_.policy_name; 

QUERY PLAN 
HashAggregate (cost=209498.38..209498.40 rows=2 width=56) (actual time=2475.980..2475.981 rows=2 loops=1) 
    -> Seq Scan on rule_traffic this_ (cost=0.00..209498.35 rows=4 width=56) (actual time=1631.945..2475.950 rows=3 loops=1) 
    Filter: ((policy_name IS NULL) AND (device_id = 11) AND ((rule_uid = 'f6c0dc29-e741-4f9a-adf1-f11d18768af3'::uuid) OR (rule_uid = 'c1a12087-2d85-4e44-a115-f9cad7ec915e'::uuid))) 
Total runtime: 2476.038 ms 
(4 rows) 

SETTING seqscan = ложь:

securetrack=# SET enable_seqscan=false; 
SET 
securetrack=# explain analyze select max(this_.id) as y0_, this_.rule_uid as y1_, this_.policy_name as y2_ from rule_traffic this_ where this_.device_id=11 and ((this_.rule_uid='f6c0dc29-e741-4f9a-adf1-f11d18768af3' and this_.policy_name is null) OR (this_.rule_uid = 'c1a12087-2d85-4e44-a115-f9cad7ec915e' and this_.policy_name is null)) group by this_.rule_uid, this_.policy_name; 
                          QUERY PLAN 
HashAggregate (cost=371469.08..371469.10 rows=2 width=56) (actual time=2936.608..2936.610 rows=2 loops=1) 
    -> Bitmap Heap Scan on rule_traffic this_ (cost=197981.02..371469.05 rows=4 width=56) (actual time=2308.843..2936.577 rows=3 loops=1) 
    Recheck Cond: ((device_id = 11) AND (policy_name IS NULL)) 
    Filter: ((rule_uid = 'f6c0dc29-e741-4f9a-adf1-f11d18768af3'::uuid) OR (rule_uid = 'c1a12087-2d85-4e44-a115-f9cad7ec915e'::uuid)) 
    -> Bitmap Index Scan on unique_device_id_version_id_policy_name_uid_in_rule_traffic (cost=0.00..197981.02 rows=5774287 width=0) (actual time=1283.603..1283.603 rows=5849739 loops=1) 
      Index Cond: ((device_id = 11) AND (policy_name IS NULL)) 
Total runtime: 2936.680 ms 
(7 rows) 

выглядит как стоимость на самом деле выше. Как это могло быть?

+0

Странно, можете ли вы попробовать, что произойдет, если вы сделаете 'SET enable_seqscan = false;' перед запуском по вашему запросу? Если он по-прежнему выполняет последовательное сканирование, то есть по какой-то причине он не может использовать индекс, иначе он думал, что это плохая идея. Кстати, какая версия postgresql? – Eelke

ответ

3

PostgreSQL здесь делает правильную вещь.

Если вы посмотрите на план запроса, в котором вы заставили его использовать индекс, вы увидите, что сканирование индекса находит 5849739 строк с (device_id = 11) AND (policy_name IS NULL), все из которых необходимо перепроверять таблицей.

Теперь сканирование такой большой части индекса и повторная проверка всех найденных строк таблицы дороже, чем последовательное сканирование всей таблицы (последовательные чтения обычно быстрее, чем чтение с произвольным доступом).

Поучительно использовать EXPLAIN (ANALYZE, BUFFERS), потому что это покажет вам фактическое количество доступных блоков базы данных.

+0

спасибо! что объясняет его! – yairo