我有一个可以使用仅索引扫描的简单计数查询,但在 PostgresQL 中仍然需要很长时间!
我有一个cars
有 2 列的表,type bigint
并且active 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 使用 Index Only Scan
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 cache (
Buffers: shared hit=2806
) 上,PostgresQL 不需要从磁盘获取页面。
从那里,我无法理解为什么 PostgresQL 需要那么长时间(4.5s)来回答查询,1M 记录并不是很多记录,所有内容都已经缓存在内存中,并且索引上的数据是可见的,它不需要获取堆。
x86_64-pc-linux-gnu 上的 PostgreSQL 9.5.10,由 gcc 编译(Debian 4 在此处输入代码.9.2-10)4.9.2,64 位
我在 docker 17.09.1-ce,Macbook pro 2015 上对其进行了测试。
我对 PostgresQL 还是新手,并试图将我的知识与真实案例相结合。非常感谢,