sql - 为什么即使使用仅索引扫描,PostgresQL 计数也如此缓慢

标签 sql query-performance postgresql-9.5 database-indexes covering-index

我有一个简单的计数查询,可以使用仅索引扫描,但在 PostgresQL 中仍然需要很长时间!

我有一个 cars 2 列表格 type bigintactive boolean ,我在这些列上也有一个多列索引

CREATE TABLE cars
(
id BIGSERIAL NOT NULL
    CONSTRAINT cars_pkey PRIMARY KEY ,
type BIGINT NOT NULL ,
name VARCHAR(500) NOT NULL ,
active            BOOLEAN DEFAULT TRUE NOT NULL,
created_at        TIMESTAMP(0) WITH TIME ZONE default NOW(),
updated_at        TIMESTAMP(0) WITH TIME ZONE default NOW(),
deleted_at        TIMESTAMP(0) WITH TIME ZONE
);
CREATE INDEX cars_type_active_index ON cars(type, active);

我插入了一些有 950k 条记录的测试数据,type=1 有 600k 条记录
INSERT INTO cars (type, name) (SELECT 1, 'car-name' FROM generate_series(1,600000));
INSERT INTO cars (type, name) (SELECT 2, 'car-name' FROM generate_series(1,200000));
INSERT INTO cars (type, name) (SELECT 3, 'car-name' FROM generate_series(1,100000));
INSERT INTO cars (type, name) (SELECT 4, 'car-name' FROM generate_series(1,50000));

让我们运行 VACUUM ANALYZE 并强制 PostgresQL 使用仅索引扫描
VACUUM ANALYSE;
SET enable_seqscan = OFF;
SET enable_bitmapscan = OFF;

好的,我在 type 上有一个简单的查询和 active
EXPLAIN (VERBOSE, BUFFERS, ANALYSE) 
SELECT count(*) 
FROM cars 
WHERE type = 1 AND active = true;

结果:

Aggregate  (cost=24805.70..24805.71 rows=1 width=0) (actual time=4460.915..4460.918 rows=1 loops=1)
Output: count(*)
Buffers: shared hit=2806
->  Index Only Scan using cars_type_active_index on public.cars (cost=0.42..23304.23 rows=600590 width=0) (actual time=0.051..2257.832 rows=600000 loops=1)
        Output: type, active
        Index Cond: ((cars.type = 1) AND (cars.active = true))
        Filter: cars.active
        Heap Fetches: 0
        Buffers: shared hit=2806
Planning time: 0.213 ms
Execution time: 4461.002 ms
(11 rows)

查看查询解释结果,
  • 它使用了 Index Only Scan , 仅索引扫描,取决于 visibilities map , PostgresQL 有时需要获取表堆来检查元组的可见性,但我已经运行 VACUUM ANALYZE所以你可以看到 Heap fetch = 0 ,因此阅读索引足以回答此查询。
  • 索引的大小非常小,可以全部放在 Buffer 缓存中( Buffers: shared hit=2806 ),PostgresQL 不需要从磁盘获取页面。

  • 从那里,我无法理解为什么 PostgresQL 需要那么长时间(4.5 秒)来回答查询,1M 记录并不是很多记录,所有内容都已经缓存在内存中,并且索引上的数据是可见的,它没有需要获取堆。

    x86_64-pc-linux-gnu 上的 PostgreSQL 9.5.10,由 gcc 编译(Debian 4enter code here.9.2-10)4.9.2,64 位

    我在 docker 17.09.1-ce、Macbook pro 2015 上对其进行了测试。

    我还是 PostgresQL 的新手,并试图将我的知识与真实案例联系起来。
    非常感谢,

    最佳答案

    似乎我找到了原因,不是关于 PostgresQL 问题,而是因为在 docker 中运行。当我直接在我的 mac 中运行时,时间将在 100 毫秒左右,这已经足够快了。

    我发现的另一件事是 PostgresQL 仍然使用 seq scan 的原因。而不是 index only scan (这就是为什么我必须在测试中禁用 seq_scan 和 bitmapscan 的原因):

  • 表的大小与索引的大小相比没有那么大,如果我向表中添加更多的列或列的长度更长,则表的大小越大,可以使用索引的机会就越大。
  • random_page_cost 的默认值是 4,我的磁盘速度很快,所以我可以将它设置为 1-2,这将有助于 psql 的解释器更准确地估计成本。
  • 关于sql - 为什么即使使用仅索引扫描,PostgresQL 计数也如此缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50083597/

    相关文章:

    sql - 在 GROUP BY 中聚合 Postgres 中的 hstore

    sql - SQL 是否有标准的 XML 查询编码?

    mysql - 在不使用自连接的情况下显示详细信息

    php - 网页标题 用户名

    postgresql - 分析 PostgreSQL 执行计划

    mySQL - 查询行数和总百分比太慢

    java - 在维护类型的同时使用条件过滤 JOOQ 生成的表

    MySQL 更新在接近表末尾时变得非常慢

    sql - 在 postgresql 中编辑 jsonb 数组的字段

    postgresql - 创建聚合时出现语法错误