【问题标题】:Postgres, Simple Queries not using indexPostgres,不使用索引的简单查询
【发布时间】:2017-09-07 21:04:08
【问题描述】:

PostgreSQL 9.5.0

我有一个名为message_attachments 的表,它有1931964 行。

我在该表中搜索了一个键,即message_id。

我也总是包含deleted_at is NULL 语句(例如软删除)。

创建了一个索引:

CREATE INDEX message_attachments_message_id_idx 
   ON message_attachments (message_id) 
WHERE deleted_at IS NULL;

所以它应该直接匹配这个查询:

EXPLAIN ANALYZE 
select * 
from "message_attachments" 
where "deleted_at" is null 
  and "message_id" = 33998052;

但生成的查询计划如下所示:

Seq Scan on message_attachments  (cost=0.00..69239.91 rows=4 width=149) (actual time=1667.850..1667.850 rows=0 loops=1)
   Filter: ((deleted_at IS NULL) AND (message_id = 33998052))
   Rows Removed by Filter: 1931896
 Planning time: 0.114 ms
 Execution time: 1667.885 ms

我在整个数据库中都使用了这样的索引,但不知何故,它似​​乎不喜欢在那个特定的表上使用它。

关于基数,最多有 5 列具有相同的值。

还在该表上运行了 ANALYZE 和 VACUUM ANALYZE。

编辑 1

SET enable_seqscan to off

SET enable_seqscan to off; EXPLAIN ANALYZE select * from "message_attachments" where "deleted_at" is null and "message_id" = 33998052;
SET
                                                                           QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on message_attachments  (cost=36111.83..105378.49 rows=4 width=149) (actual time=2343.361..2343.361 rows=0 loops=1)
   Recheck Cond: (deleted_at IS NULL)
   Filter: (message_id = 33998052)
   Rows Removed by Filter: 1932233
   Heap Blocks: exact=45086
   ->  Bitmap Index Scan on message_attachments_deleted_at_index  (cost=0.00..36111.82 rows=1934453 width=0) (actual time=789.836..789.836 rows=1933784 loops=1)
         Index Cond: (deleted_at IS NULL)
 Planning time: 0.098 ms
 Execution time: 2343.425 ms

这将在该表的第二个索引上运行,如下所示:(绝对不应该使用)

CREATE INDEX message_attachments_deleted_at_index ON message_attachments USING btree (deleted_at)

编辑 2

\d+ message_attachments
                                                         Table "public.message_attachments"
   Column   |            Type             |                            Modifiers                             | Storage  | Stats target | Description
------------+-----------------------------+------------------------------------------------------------------+----------+--------------+-------------
 id         | bigint                      | not null default nextval('message_attachments_id_seq'::regclass) | plain    |              |
 created_at | timestamp without time zone | not null                                                         | plain    |              |
 updated_at | timestamp without time zone | not null                                                         | plain    |              |
 deleted_at | timestamp without time zone |                                                                  | plain    |              |
 name       | character varying(255)      | not null                                                         | extended |              |
 filename   | character varying(255)      | not null                                                         | extended |              |
 content    | bytea                       |                                                                  | extended |              |
 hash       | character varying(255)      | not null                                                         | extended |              |
 mime       | character varying(255)      | not null                                                         | extended |              |
 size       | bigint                      | not null                                                         | plain    |              |
 message_id | bigint                      | not null                                                         | plain    |              |
Indexes:
    "message_attachments_pkey" PRIMARY KEY, btree (id)
    "message_attachments_deleted_at_index" btree (deleted_at)
    "message_attachments_message_id_idx" btree (message_id) WHERE deleted_at IS NULL
Foreign-key constraints:
    "message_attachments_message_id_foreign" FOREIGN KEY (message_id) REFERENCES messages(id)

编辑3

在热备用主机上的行为完全相同。 (它是最新的)

编辑4

select seq_scan,seq_tup_read,idx_scan,idx_tup_fetch,n_live_tup,pg_stat_all_tables.n_dead_tup,last_analyze,pg_stat_all_tables.analyze_count,pg_stat_all_tables.last_autoanalyze from pg_stat_all_tables where relname = 'message_attachments';
 seq_scan |  seq_tup_read  | idx_scan | idx_tup_fetch | n_live_tup | n_dead_tup |         last_analyze          | analyze_count |       last_autoanalyze
----------+----------------+----------+---------------+------------+------------+-------------------------------+---------------+-------------------------------
 18728036 | 26379554229720 |  1475541 |     808566894 |    1934435 |      28052 | 2017-04-12 09:48:34.638184+02 |            68 | 2017-02-02 18:41:05.902214+01

select * from pg_stat_all_indexes where relname = 'message_attachments';
 relid  | indexrelid | schemaname |       relname       |             indexrelname             | idx_scan | idx_tup_read | idx_tup_fetch
--------+------------+------------+---------------------+--------------------------------------+----------+--------------+---------------
 113645 |     113652 | public     | message_attachments | message_attachments_pkey             |  1475563 |    804751648 |     802770401
 113645 |     113659 | public     | message_attachments | message_attachments_deleted_at_index |        3 |      5801165 |             0
 113645 |   20954507 | public     | message_attachments | message_attachments_message_id_idx   |        0 |            0 |             0

【问题讨论】:

  • 尝试SET enable_seqscan to off 并再次运行分析以检查成本
  • 您使用的是哪个 Postgres 版本?你真的确定你分析了表格吗? Postgres 估计只有 4 行(当表有近 200 万行时)这一事实似乎表明统计数据不是最新的。
  • @a_horse_with_no_name 这绝对是奇怪的!我使用的是 9.5,在 pg_class 中它告诉我有 1934020 个元组,这 4 行的估计值来自哪里?我确实确实运行了 VACUUM ANALYZE message_attachments 和 ANALYZE message_attachments
  • @VaoTsun 添加了带有 seqscan 的查询计划,对我来说它看起来根本看不到索引!
  • 嗯。出于好奇 - 可能首先 inde 无法使用?.. 请添加 \d+ message_attachments 以获取完整图片

标签: postgresql indexing


【解决方案1】:

好的,我刚刚解决了这个问题。

我们以某种方式为一个在 php 中被杀死的查询设置了一个挂起的 LOCK,但几天前从未退出过 postgres 上的进程。

因此,对于遇到相同问题的每个人,请检查您的 LOCKS:

SELECT relation::regclass, * FROM pg_locks WHERE NOT GRANTED;

另外,如果几天前有任何连接打开:

select * from pg_stat_activity order by query_start limit 10;

【讨论】:

  • 我正想问您是否有任何“空闲交易”会话...
  • 您锁定了索引,而不是表?并且您可以重建该索引,但不能用于选择?..
  • 不,锁在完全(插入客户)不同的表上,它甚至没有激活,它正在等待被授予。并且在数据库中的任何地方都没有使用新创建的索引。
  • 我很困惑,看起来像是在给你解释 :) 我不明白 - 锁如何影响执行计划?..
  • 不要问我,否则我不会打开这个问题 :D 对我来说,问题似乎是计划者挂在某个 xact 上(不确定它是否像那样工作),因此在该 xact(几天前)不存在的所有索引都被简单地忽略了。
猜你喜欢
  • 2016-04-05
  • 1970-01-01
  • 2012-04-26
  • 1970-01-01
  • 2015-09-15
  • 1970-01-01
  • 2016-10-13
  • 2020-09-01
  • 2019-09-12
相关资源
最近更新 更多