为什么 Postgres 更喜欢 seq 扫描而不是具有明确 where 条件的部分索引?

影碟

我有一个简单的查询,如select * from xxx where col is not null limit 10. 我不知道为什么 Postgres 更喜欢 seq 扫描,这比部分索引慢得多(我已经分析了表)。如何调试这样的问题?

该表有超过 400 万行。大约 350,000 行满意pid is not null

我认为成本估算可能有问题。seq 扫描的成本低于索引扫描。但是如何深入研究呢?

我有一个猜测,但不确定。非空行约占总行数的 10%。这意味着当 seq 扫描 100 行时,它可能会得到 10 行不为空。并且它认为 seq 扫描 100 行的成本低于索引扫描 10 行然后随机获取 10 行的成本。是吗?

> \d data_import
+--------------------+--------------------------+----------------------------------------------------------------------------+
| Column             | Type                     | Modifiers                                                                  |
|--------------------+--------------------------+----------------------------------------------------------------------------|
| id                 | integer                  |  not null default nextval('data_import_id_seq'::regclass) |
| name               | character varying(64)    |                                                                            |
| market_activity_id | integer                  |  not null                                                                  |
| hmsr_id            | integer                  |  not null default (-1)                                                     |
| site_id            | integer                  |  not null default (-1)                                                     |
| hmpl_id            | integer                  |  not null default (-1)                                                     |
| hmmd_id            | integer                  |  not null default (-1)                                                     |
| hmci_id            | integer                  |  not null default (-1)                                                     |
| hmkw_id            | integer                  |  not null default (-1)                                                     |
| creator_id         | integer                  |                                                                            |
| created_at         | timestamp with time zone |                                                                            |
| updated_at         | timestamp with time zone |                                                                            |
| bias               | integer                  |                                                                            |
| pid                | character varying(128)   |  default NULL::character varying                                           |
+--------------------+--------------------------+----------------------------------------------------------------------------+
Indexes:
    "data_import_pkey" PRIMARY KEY, btree (id)
    "unique_hmxx" UNIQUE, btree (site_id, hmsr_id, hmpl_id, hmmd_id, hmci_id, hmkw_id) WHERE pid IS NULL
    "data_import_pid_idx" UNIQUE, btree (pid) WHERE pid IS NOT NULL
    "data_import_created_at_idx" btree (created_at)
    "data_import_hmsr_id" btree (hmsr_id)
    "data_import_updated_at_idx" btree (updated_at)



> set enable_seqscan to false;
apollon> explain (analyse, verbose)  select * from data_import where pid is not null limit 10
+-------------------------------------------------------------------------------------------------------------------------------------------------------------
| QUERY PLAN
|-------------------------------------------------------------------------------------------------------------------------------------------------------------
| Limit  (cost=0.42..5.68 rows=10 width=84) (actual time=0.059..0.142 rows=10 loops=1)
|   Output: id, name, market_activity_id, hmsr_id, site_id, hmpl_id, hmmd_id, hmci_id, hmkw_id, creator_id, created_at, updated_at, bias, pid
|   ->  Index Scan using data_import_pid_idx on public.data_import  (cost=0.42..184158.08 rows=350584 width=84) (actual time
|         Output: id, name, market_activity_id, hmsr_id, site_id, hmpl_id, hmmd_id, hmci_id, hmkw_id, creator_id, created_at, updated_at, bias, pid
|         Index Cond: (data_import.pid IS NOT NULL)
| Planning time: 0.126 ms
| Execution time: 0.177 ms
+-------------------------------------------------------------------------------------------------------------------------------------------------------------
EXPLAIN
Time: 0.054s

> set enable_seqscan to true;
> explain (analyse, verbose)  select * from data_import where pid is not null limit 10
+---------------------------------------------------------------------------------------------------------------------------------------------------+
| QUERY PLAN                                                                                                                                        |
|---------------------------------------------------------------------------------------------------------------------------------------------------|
| Limit  (cost=0.00..2.37 rows=10 width=84) (actual time=407.042..407.046 rows=10 loops=1)                                                          |
|   Output: id, name, market_activity_id, hmsr_id, site_id, hmpl_id, hmmd_id, hmci_id, hmkw_id, creator_id, created_at, updated_at, bias, pid       |
|   ->  Seq Scan on public.data_import  (cost=0.00..83016.60 rows=350584 width=84) (actual time=407.041..407.045 rows=10 loops=1)  |
|         Output: id, name, market_activity_id, hmsr_id, site_id, hmpl_id, hmmd_id, hmci_id, hmkw_id, creator_id, created_at, updated_at, bias, pid |
|         Filter: (data_import.pid IS NOT NULL)                                                                                    |
|         Rows Removed by Filter: 3672502                                                                                                           |
| Planning time: 0.116 ms                                                                                                                           |
| Execution time: 407.078 ms                                                                                                                        |
+---------------------------------------------------------------------------------------------------------------------------------------------------+
EXPLAIN
Time: 0.426s
劳伦兹·阿尔伯

你的问题是

Rows Removed by Filter: 3672502

PostgreSQL 知道值的分布以及它们如何与物理表布局相关联,但它不知道表开头的行都为 NULL pid

如果 NULL 分布均匀,顺序扫描将很快找到 10 个命中并停止,但实际上,它必须读取 3672512 行才能找到 10 个匹配的行。

如果您在 之前添加ORDER BY pid(即使您不需要它)LIMIT,优化器将做正确的事情。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Postgres更喜欢昂贵的ST_Intersects()而不是便宜的索引

来自分类Dev

为什么更喜欢Typeclass而不是Inheritance?

来自分类Dev

为什么对游戏逻辑更喜欢update()而不是didFinishUpdate?

来自分类Dev

为什么更喜欢defaults()而不是Javascript原型?

来自分类Dev

为什么 postgres 计划的“扫描索引(btree)”阶段返回所有行?

来自分类Dev

为什么在`accursedUnutterablePerformIO`中没有`seq`?

来自分类Dev

为什么我们在Java中更喜欢基元而不是盒装基元

来自分类Dev

为什么我们更喜欢在$ q中使用$ q而不是$ http

来自分类Dev

为什么程序员更喜欢O(N ^ 3)而不是O(N ^ 2)

来自分类Dev

为什么更喜欢隐式val而不是隐式对象

来自分类Dev

为什么我应该更喜欢OneNote App而不是MS Office OneNote?

来自分类Dev

创建空文件时,为什么人们会更喜欢“触摸文件”而不是“:>>文件”?

来自分类Dev

为什么我更喜欢元类而不是Python中超类的继承

来自分类Dev

为什么 SO 上的人更喜欢 CASE WHEN 而不是其他选择?

来自分类Dev

Postgres-具有多个where子句的索引

来自分类Dev

在Postgres中索引部分索引的条件

来自分类Dev

为什么更喜欢Ember。$()vs $()

来自分类Dev

为什么PHP比__callStatic()更喜欢__call()?

来自分类Dev

为什么我比qDebug更喜欢qCDebug?

来自分类Dev

为什么更喜欢Ember。$()vs $()

来自分类Dev

什么时候更喜欢Hadoop MapReduce而不是Spark?

来自分类Dev

什么时候更喜欢LinkedBlockingQueue而不是ArrayBlockingQueue?

来自分类Dev

为什么查询具有索引时为什么要进行聚集索引扫描

来自分类Dev

为什么Postgres进行顺序扫描,索引将返回小于1%的数据?

来自分类Dev

当使用覆盖索引时,为什么Postgres仍然进行位图堆扫描?

来自分类Dev

为什么Postgres不使用索引?

来自分类Dev

为什么Postgres不使用索引?

来自分类Dev

为什么Seq.containsSlice不是类型安全的?

来自分类Dev

为什么 postgres 虚拟列会破坏拉起条件并强制子查询扫描?

Related 相关文章

  1. 1

    Postgres更喜欢昂贵的ST_Intersects()而不是便宜的索引

  2. 2

    为什么更喜欢Typeclass而不是Inheritance?

  3. 3

    为什么对游戏逻辑更喜欢update()而不是didFinishUpdate?

  4. 4

    为什么更喜欢defaults()而不是Javascript原型?

  5. 5

    为什么 postgres 计划的“扫描索引(btree)”阶段返回所有行?

  6. 6

    为什么在`accursedUnutterablePerformIO`中没有`seq`?

  7. 7

    为什么我们在Java中更喜欢基元而不是盒装基元

  8. 8

    为什么我们更喜欢在$ q中使用$ q而不是$ http

  9. 9

    为什么程序员更喜欢O(N ^ 3)而不是O(N ^ 2)

  10. 10

    为什么更喜欢隐式val而不是隐式对象

  11. 11

    为什么我应该更喜欢OneNote App而不是MS Office OneNote?

  12. 12

    创建空文件时,为什么人们会更喜欢“触摸文件”而不是“:>>文件”?

  13. 13

    为什么我更喜欢元类而不是Python中超类的继承

  14. 14

    为什么 SO 上的人更喜欢 CASE WHEN 而不是其他选择?

  15. 15

    Postgres-具有多个where子句的索引

  16. 16

    在Postgres中索引部分索引的条件

  17. 17

    为什么更喜欢Ember。$()vs $()

  18. 18

    为什么PHP比__callStatic()更喜欢__call()?

  19. 19

    为什么我比qDebug更喜欢qCDebug?

  20. 20

    为什么更喜欢Ember。$()vs $()

  21. 21

    什么时候更喜欢Hadoop MapReduce而不是Spark?

  22. 22

    什么时候更喜欢LinkedBlockingQueue而不是ArrayBlockingQueue?

  23. 23

    为什么查询具有索引时为什么要进行聚集索引扫描

  24. 24

    为什么Postgres进行顺序扫描,索引将返回小于1%的数据?

  25. 25

    当使用覆盖索引时,为什么Postgres仍然进行位图堆扫描?

  26. 26

    为什么Postgres不使用索引?

  27. 27

    为什么Postgres不使用索引?

  28. 28

    为什么Seq.containsSlice不是类型安全的?

  29. 29

    为什么 postgres 虚拟列会破坏拉起条件并强制子查询扫描?

热门标签

归档