AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 16612
Accepted
dezso
dezso
Asked: 2012-04-18 03:34:27 +0800 CST2012-04-18 03:34:27 +0800 CST 2012-04-18 03:34:27 +0800 CST

简单连接中未使用的主键索引

  • 772

我有以下表格和索引定义:

CREATE TABLE munkalap (
    munkalap_id serial PRIMARY KEY,
    ...
);

CREATE TABLE munkalap_lepes (
    munkalap_lepes_id serial PRIMARY KEY,
    munkalap_id integer REFERENCES munkalap (munkalap_id),
    ...
);

CREATE INDEX idx_munkalap_lepes_munkalap_id ON munkalap_lepes (munkalap_id);

为什么以下查询中没有使用 munkalap_id 上的任何索引?

EXPLAIN ANALYZE SELECT ml.* FROM munkalap m JOIN munkalap_lepes ml USING (munkalap_id);

QUERY PLAN
Hash Join  (cost=119.17..2050.88 rows=38046 width=214) (actual time=0.824..18.011 rows=38046 loops=1)
  Hash Cond: (ml.munkalap_id = m.munkalap_id)
  ->  Seq Scan on munkalap_lepes ml  (cost=0.00..1313.46 rows=38046 width=214) (actual time=0.005..4.574 rows=38046 loops=1)
  ->  Hash  (cost=78.52..78.52 rows=3252 width=4) (actual time=0.810..0.810 rows=3253 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 115kB
        ->  Seq Scan on munkalap m  (cost=0.00..78.52 rows=3252 width=4) (actual time=0.003..0.398 rows=3253 loops=1)
Total runtime: 19.786 ms

即使我添加一个过滤器也是一样的:

EXPLAIN ANALYZE SELECT ml.* FROM munkalap m JOIN munkalap_lepes ml USING (munkalap_id) WHERE NOT lezarva;

QUERY PLAN
Hash Join  (cost=79.60..1545.79 rows=1006 width=214) (actual time=0.616..10.824 rows=964 loops=1)
  Hash Cond: (ml.munkalap_id = m.munkalap_id)
  ->  Seq Scan on munkalap_lepes ml  (cost=0.00..1313.46 rows=38046 width=214) (actual time=0.007..5.061 rows=38046 loops=1)
  ->  Hash  (cost=78.52..78.52 rows=86 width=4) (actual time=0.587..0.587 rows=87 loops=1)
        Buckets: 1024  Batches: 1  Memory Usage: 4kB
        ->  Seq Scan on munkalap m  (cost=0.00..78.52 rows=86 width=4) (actual time=0.014..0.560 rows=87 loops=1)
              Filter: (NOT lezarva)
Total runtime: 10.911 ms
postgresql performance
  • 2 2 个回答
  • 17072 Views

2 个回答

  • Voted
  1. Best Answer
    dbenhur
    2012-04-21T15:11:44+08:002012-04-21T15:11:44+08:00

    许多人听说过“顺序扫描不好”的指导,并试图将其从计划中消除,但这并不是那么简单。如果查询要覆盖表中的每一行,顺序扫描是获取这些行的最快方法。这就是您的原始连接查询使用 seq 扫描的原因,因为两个表中的所有行都是必需的。

    在规划查询时,Postgres 的规划器会估计不同可能方案下各种操作(计算、顺序和随机 IO)的成本,并选择它估计成本最低的计划。从旋转存储(磁盘)进行 IO 时,随机 IO 通常比顺序 IO 慢很多,random_page_cost 和 seq_page_cost的默认 pg 配置估计成本差异为 4:1。

    在考虑使用索引的连接或过滤方法与顺序扫描表的方法时,这些考虑因素会起作用。使用索引时,计划可能会通过索引快速找到一行,然后必须考虑随机读取块来解析行数据。在您的第二个查询添加了过滤谓词的情况下WHERE NOT lezarva,您可以看到这如何影响 EXPLAIN ANALYZE 结果中的计划估计。规划器估计连接产生的 1006 行(与实际结果集 964 非常接近)。鉴于较大的表 munkalap_lepes 包含大约 38K 行,规划器看到连接将不得不访问表中大约 1006/38046 或 1/38 的行。它还知道平均行宽是 214 字节,一个块是 8K,所以大约有 38 行/块。

    有了这些统计信息,计划者认为连接很可能必须读取所有或大部分表的数据块。由于索引查找也不是免费的,并且相对于 IO,扫描评估过滤条件的块的计算非常便宜,因此规划器选择顺序扫描表并在计算 seq 扫描时避免索引开销和随机读取会更快。

    在现实世界中,数据通常通过 OS 页面缓存在内存中可用,因此并非每个块读取都需要 IO。很难预测缓存对给定查询的有效性,但 Pg 计划器确实使用了一些简单的启发式方法。配置值Effective_cache_size 通知规划者估计产生实际 IO 成本的可能性。较大的值将导致它估计随机 IO 的成本较低,因此可能会将其偏向于索引驱动方法而不是顺序扫描。

    • 30
  2. a_horse_with_no_name
    2012-04-18T04:16:48+08:002012-04-18T04:16:48+08:00

    您正在从两个表中检索所有行,因此使用索引扫描并没有真正的好处。仅当您从表中选择几行(通常小于 10%-15%)时,索引扫描才有意义

    • 8

相关问题

  • PostgreSQL 中 UniProt 的生物序列

  • 如何确定是否需要或需要索引

  • 我在哪里可以找到mysql慢日志?

  • 如何优化大型数据库的 mysqldump?

  • PostgreSQL 9.0 Replication 和 Slony-I 有什么区别?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何查看 Oracle 中的数据库列表?

    • 8 个回答
  • Marko Smith

    mysql innodb_buffer_pool_size 应该有多大?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    从 .frm 和 .ibd 文件恢复表?

    • 10 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    如何选择每组的第一行?

    • 6 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    pedrosanta 使用 psql 列出数据库权限 2011-08-04 11:01:21 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST
  • Martin Hope
    bernd_k 什么时候应该使用唯一约束而不是唯一索引? 2011-01-05 02:32:27 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve