分区 table 上的 Postgres 查询比非分区 table 慢 2 倍
Postgres query on partitioned table 2x slower than non-partitioned table
我们有一个包含 400 万条记录的 table,我们为它创建了分区 table,假设 select 查询在启用分区的 table 上会更快.但是,启用分区的 table 上的 select 慢了 2 倍!!
正常table(24毫秒)
explain analyse select * from tbl_original where device_info_id = 5;
启用分区table(49 毫秒)
explain analyse select * from tbl_partitioned where device_info_id = 5;
以下是 EXPLAIN ANALYZE
命令对 tbl_original
的输出:
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on tbl_original (cost=61.19..9515.02 rows=2679 width=379) (actual time=0.297..13.008 rows=3369 loops=1)
Recheck Cond: (device_info_id = 5)
Heap Blocks: exact=554
-> Bitmap Index Scan on idx_tbl_original (cost=0.00..60.52 rows=2679 width=0) (actual time=0.232..0.232 rows=3369 loops=1)
Index Cond: (device_info_id = 5)
Planning time: 0.087 ms
Execution time: 24.890 ms
以下是 tbl_partitioned
的 EXPLAIN ANALYZE
命令的输出
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Append (cost=0.00..6251.14 rows=3697 width=404) (actual time=0.034..36.635 rows=3369 loops=1)
-> Seq Scan on tbl_partitioned (cost=0.00..0.00 rows=1 width=1069) (actual time=0.006..0.006 rows=0 loops=1)
Filter: (device_info_id = 5)
-> Index Scan using idx_tbl_partitioned_p1 on tbl_partitioned_p1 (cost=0.42..6251.14 rows=3696 width=404) (actual time=0.017..12.922 rows=3369 loops=1)
Index Cond: (device_info_id = 5)
Planning time: 0.184 ms
Execution time: 49.129 ms
看起来分区查询中最昂贵的操作是 索引扫描 占用 6251.14 个单元。但是,考虑到分区 table 与原始 table 相比的大小,此索引扫描应该非常快。不确定我们是否遗漏了任何明显的东西!
任何对优化 query/partitioned table 的帮助将不胜感激。
注意:分区 table 是使用以下内容创建的:
CREATE TABLE tbl_partitioned (LIKE tbl_original);
CREATE TABLE tbl_partitioned_p1 (
CONSTRAINT pk_tbl_partitioned_p1 PRIMARY KEY (id),
CONSTRAINT ck_tbl_partitioned_p1 CHECK ( device_info_id < 10 )
) INHERITS (tbl_partitioned);
CREATE INDEX idx_tbl_partitioned_p1 ON tbl_partitioned_p1 (device_info_id);
CREATE INDEX idx_tbl_partitioned ON tbl_partitioned (device_info_id);
INSERT INTO tbl_partitioned_p1 SELECT * from tbl_original where device_info_id < 10;
table 的大小是:
select count(*) from tbl_partitioned; -- 413696 rows
select count(*) from tbl_original; -- 4417025 rows
select count(*) from tbl_original where device_info_id = 5; -- 3369 rows
constraint_exclusion
设置为 partition
尝试获取更多解释数据,例如:
explain (ANALYZE, TIMING, COSTS, BUFFERS, VERBOSE) select * from
tbl_original where device_info_id = 5;
特别要注意输出中的 "hits",例如:
Buffers: shared hit=4 read=224
Read=xxx 表示必须从磁盘读取一个块。 Hit= 表示它来自 RAM(共享缓冲区)。您的更多数据可能在共享缓冲区中——性能在很大程度上取决于此。
我们有一个包含 400 万条记录的 table,我们为它创建了分区 table,假设 select 查询在启用分区的 table 上会更快.但是,启用分区的 table 上的 select 慢了 2 倍!!
正常table(24毫秒)
explain analyse select * from tbl_original where device_info_id = 5;
启用分区table(49 毫秒)
explain analyse select * from tbl_partitioned where device_info_id = 5;
以下是 EXPLAIN ANALYZE
命令对 tbl_original
的输出:
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on tbl_original (cost=61.19..9515.02 rows=2679 width=379) (actual time=0.297..13.008 rows=3369 loops=1)
Recheck Cond: (device_info_id = 5)
Heap Blocks: exact=554
-> Bitmap Index Scan on idx_tbl_original (cost=0.00..60.52 rows=2679 width=0) (actual time=0.232..0.232 rows=3369 loops=1)
Index Cond: (device_info_id = 5)
Planning time: 0.087 ms
Execution time: 24.890 ms
以下是 tbl_partitioned
EXPLAIN ANALYZE
命令的输出
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Append (cost=0.00..6251.14 rows=3697 width=404) (actual time=0.034..36.635 rows=3369 loops=1)
-> Seq Scan on tbl_partitioned (cost=0.00..0.00 rows=1 width=1069) (actual time=0.006..0.006 rows=0 loops=1)
Filter: (device_info_id = 5)
-> Index Scan using idx_tbl_partitioned_p1 on tbl_partitioned_p1 (cost=0.42..6251.14 rows=3696 width=404) (actual time=0.017..12.922 rows=3369 loops=1)
Index Cond: (device_info_id = 5)
Planning time: 0.184 ms
Execution time: 49.129 ms
看起来分区查询中最昂贵的操作是 索引扫描 占用 6251.14 个单元。但是,考虑到分区 table 与原始 table 相比的大小,此索引扫描应该非常快。不确定我们是否遗漏了任何明显的东西!
任何对优化 query/partitioned table 的帮助将不胜感激。
注意:分区 table 是使用以下内容创建的:
CREATE TABLE tbl_partitioned (LIKE tbl_original);
CREATE TABLE tbl_partitioned_p1 (
CONSTRAINT pk_tbl_partitioned_p1 PRIMARY KEY (id),
CONSTRAINT ck_tbl_partitioned_p1 CHECK ( device_info_id < 10 )
) INHERITS (tbl_partitioned);
CREATE INDEX idx_tbl_partitioned_p1 ON tbl_partitioned_p1 (device_info_id);
CREATE INDEX idx_tbl_partitioned ON tbl_partitioned (device_info_id);
INSERT INTO tbl_partitioned_p1 SELECT * from tbl_original where device_info_id < 10;
table 的大小是:
select count(*) from tbl_partitioned; -- 413696 rows
select count(*) from tbl_original; -- 4417025 rows
select count(*) from tbl_original where device_info_id = 5; -- 3369 rows
constraint_exclusion
设置为 partition
尝试获取更多解释数据,例如:
explain (ANALYZE, TIMING, COSTS, BUFFERS, VERBOSE) select * from tbl_original where device_info_id = 5;
特别要注意输出中的 "hits",例如:
Buffers: shared hit=4 read=224
Read=xxx 表示必须从磁盘读取一个块。 Hit= 表示它来自 RAM(共享缓冲区)。您的更多数据可能在共享缓冲区中——性能在很大程度上取决于此。