Nie*_*ian 3 postgresql performance
嗨,我在Heroku上运行postgresql 9.1.6,他们的Ika计划(7,5gb ram).我有一张叫做汽车的桌子.我需要做以下事情:
SELECT COUNT(*) FROM "cars" WHERE "cars"."reference_id" = 'toyota_hilux'
Run Code Online (Sandbox Code Playgroud)
现在这需要花费大量的时间(64秒!!!)
Aggregate (cost=2849.52..2849.52 rows=1 width=0) (actual time=63388.390..63388.391 rows=1 loops=1)
-> Bitmap Heap Scan on cars (cost=24.76..2848.78 rows=1464 width=0) (actual time=1169.581..63387.361 rows=739 loops=1)
Recheck Cond: ((reference_id)::text = 'toyota_hilux'::text)
-> Bitmap Index Scan on index_cars_on_reference_id (cost=0.00..24.69 rows=1464 width=0) (actual time=547.530..547.530 rows=832 loops=1)
Index Cond: ((reference_id)::text = 'toyota_hilux'::text)
Total runtime: 64112.412 ms
Run Code Online (Sandbox Code Playgroud)
一点背景:
该表包含大约3.2米的行,而我正在尝试依赖的列具有以下设置:
reference_id character varying(50);
Run Code Online (Sandbox Code Playgroud)
和索引:
CREATE INDEX index_cars_on_reference_id
ON cars
USING btree
(reference_id COLLATE pg_catalog."default" );
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?我希望这种表现不是我应该期待的 - 或者我应该这样做?
什么@Satya在他的评论中称并不完全正确.在存在匹配索引的情况下,如果表统计信息意味着它将返回超过表的大约5%(取决于),则计划程序仅选择全表扫描,因为扫描整个表的速度更快.
从您自己的问题中可以看出,您的查询并非如此.它使用位图索引扫描,然后是位图堆扫描.虽然我本来期望一个简单的索引扫描.(?)
我在解释输出中还注意到另外两件事:
第一次扫描找到832行,而第二次扫描将计数减少到739.这表明你的索引中有许多死元组.
检查每个步骤后的执行时间,EXPLAIN ANALYZE并将结果添加到您的问题中:
首先,使用EXPLAIN ANALYZE重新运行查询两到三次以填充缓存.与第一次相比,上次运行的结果是什么?
下一个:
VACUUM ANALYZE cars;
Run Code Online (Sandbox Code Playgroud)
重新运行.
如果你在表上有很多写操作,我会设置一个低于100的填充因子.
ALTER TABLE cars SET (fillfactor=90);
Run Code Online (Sandbox Code Playgroud)
如果您的行大小或您有大量的写入操作,则降低.然后:
VACUUM FULL ANALYZE cars;
Run Code Online (Sandbox Code Playgroud)
这需要一段时间.重新运行.
或者,如果您能负担得起(并且其他重要查询没有相反的要求):
CLUSTER cars USING index_cars_on_reference_id;
Run Code Online (Sandbox Code Playgroud)
这重写表中的索引,它应该使这种查询的物理顺序多快.
如果您需要非常快,请car_type使用serial主键创建一个表并从表中引用它cars.这会将必要的索引缩小到现在的一小部分.
不用说你在尝试任何这个之前做了备份.
CREATE temp TABLE car_type (
car_type_id serial PRIMARY KEY
, car_type text
);
INSERT INTO car_type (car_type)
SELECT DISTINCT car_type_id FROM cars ORDER BY car_type_id;
ANALYZE car_type;
CREATE UNIQUE INDEX car_type_uni_idx ON car_type (car_type); -- unique types
ALTER TABLE cars RENAME COLUMN car_type_id TO car_type; -- rename old col
ALTER TABLE cars ADD COLUMN car_type_id int; -- add new int col
UPDATE cars c
SET car_type_id = ct.car_type_id
FROM car_type ct
WHERE ct.car_type = c.car_type;
ALTER TABLE cars DROP COLUMN car_type; -- drop old varchar col
CREATE INDEX cars_car_type_id_idx ON cars (car_type_id);
ALTER TABLE cars
ADD CONSTRAINT cars_car_type_id_fkey FOREIGN KEY (car_type_id )
REFERENCES car_type (car_type_id) ON UPDATE CASCADE; -- add fk
VACUUM FULL ANALYZE cars;
Run Code Online (Sandbox Code Playgroud)
或者,如果你想全力以赴:
CLUSTER cars USING cars_car_type_id_idx;
Run Code Online (Sandbox Code Playgroud)
您的查询现在看起来像这样:
SELECT count(*)
FROM cars
WHERE car_type_id = (SELECT car_type_id FROM car_type
WHERE car_type = 'toyota_hilux')
Run Code Online (Sandbox Code Playgroud)
而且应该更快.主要是因为索引和表现在较小,但也因为integer处理比varchar处理更快.但是,相对于varchar列上的聚簇表,增益不会很大.
一个受欢迎的副作用:如果你必须重命名一个类型,它现在是一个小UPDATE到一排,而不是弄乱大表.
| 归档时间: |
|
| 查看次数: |
255 次 |
| 最近记录: |