【问题标题】:Why is my postgreSQL index not being used?为什么我的 postgreSQL 索引没有被使用?
【发布时间】:2012-07-30 08:04:11
【问题描述】:

当我使用以下查询时,响应时间真的很糟糕(有时超过一分钟!)。

select * from cdr where start_time < now() - interval '4 hours' and final = 0 limit 50 

我正在尝试获取 final=0 且 starttime 超过 4 小时的记录。 以下是我在桌子上的索引:

CREATE INDEX "cdr_Final_ix"
ON cdr
USING btree
(start_time , final );

以下是解释分析:

"Limit  (cost=0.00..167.81 rows=50 width=188) (actual time=64491.409..64650.635 rows=11 loops=1)"
"  ->  Seq Scan on cdr  (cost=0.00..749671.06 rows=223372 width=188) (actual time=64491.407..64650.625 rows=11 loops=1)"
"Filter: ((final = 0) AND (start_time < (now() - '04:00:00'::interval)))"
"Total runtime: 64650.690 ms"

任何帮助将不胜感激。谢谢,阿里

【问题讨论】:

  • 多少行?有多少符合条件?注意:你没有order by
  • 顺序是什么对我来说并不重要。表中的行数在一天中在约 10K 到 500 万之间变化。符合条件的数量在 0 到 200 之间变化,因为我通常在查询后更新最终结果。如果我不是最新的,那么可以有超过 100K 的资格。
  • 我得到 40K 行的索引扫描
  • 我使用的是 9.1 版。当我说“start_time = '7/29/2012'”时,我能够成功使用索引,但这对我的查询没有帮助。当它比较不等式时,它不会选择索引。如果我从 postgres 读取的程序正常工作,那么 final = 0 的值应该始终在当前日期的 4 小时内,并且稍微超出 4 小时窗口。
  • 使用部分索引 (WHERE final=0) 我仍然得到索引扫描,结果在亚毫秒时间内,正常索引 100--200 毫秒,大约 250 万行更新:我会作为答案发布。

标签: performance postgresql datetime indexing


【解决方案1】:
-- DROP SCHEMA tmp CASCADE;
-- CREATE SCHEMA tmp ;
SET search_path='tmp';

-- Generate some data
CREATE TABLE cdr
        ( start_time TIMESTAMP NOT NULL
        , final INTEGER
        );
INSERT INTO cdr (start_time,final)
SELECT gs, random() * 1000
FROM generate_series('2012-07-01 00:00:00', '2012-08-01 00:00:00', '1 s'::interval) gs
        ;
DROP INDEX "cdr_Final_ix";
CREATE INDEX "cdr_Final_ix"
ON cdr
USING btree
(start_time , final )
WHERE final = 0 -- partial index here
;

-- Do some data-massaging
-- UPDATE cdr
-- SET final = random() * 100
-- WHERE final = 0
-- AND random() < 0.2 ;

VACUUM ANALYZE cdr;

-- SET tuning to default (the worst possible)
SET random_page_cost = 4;
SET work_mem = 64;
SET effective_cache_size = 64;
-- SET shared_buffers = 64;

EXPLAIN ANALYZE
SELECT * from cdr
WHERE start_time < now() - interval '4 hours'
AND final = 0
ORDER BY start_time
LIMIT 50
        ;

结果:

                                                           QUERY PLAN                                                            
----------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.01..88.49 rows=50 width=12) (actual time=0.191..0.452 rows=50 loops=1)
   ->  Index Scan using "cdr_Final_ix" on cdr  (cost=0.01..4310.95 rows=2436 width=12) (actual time=0.188..0.321 rows=50 loops=1)
         Index Cond: ((start_time < (now() - '04:00:00'::interval)) AND (final = 0))
 Total runtime: 0.569 ms
(4 rows)

【讨论】:

  • 好的。听起来不错。我改变了我的索引,我现在正在真空分析。数据按摩的目的是什么?是否有必要因为我不想更改我的数据?
  • 不,数据按摩只是为了改变“最终”在我的合成数据集中的分布。我还将日期移至 2012-07-30 + 一个月,结果计划没有变化。
  • 太棒了!有效!它拿起指数。非常感谢。不过,我得到的查询计划与您不同。查看下一条评论
  • "限制(成本=204.54..391.71 行=50 宽度=188)(实际时间=0.469..0.533 行=50 循环=1)""-> cdr 上的位图堆扫描(成本=204.54..21298.88 行=5635 宽度=188) (实际时间=0.469..0.520 行=50 循环=1)" " 重新检查条件: ((start_time Bitmap Index Scan on "cdr_Final_ix" (cost=0.00..203.13 rows=5635 width=0) (实际时间=0.394..0.394 rows=1194 loops=1) " " Index Cond: ((start_time
  • 可调参数 {random_page_cost,work_mem,effective_cache_size,shared_buffers} 加上可能值的分布(或其估计值)YMMV...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-10
  • 1970-01-01
  • 2013-02-22
  • 1970-01-01
相关资源
最近更新 更多