为什么以下Postgres SQL查询需要这么长时间?

del*_*ber 5 sql postgresql

原始查询如下

SELECT "TIME", "TRADEPRICE"
  FROM "YEAR" where "DATE"='2010-03-01' 
  and "SECURITY"='STW.AX' 
  AND "TIME" < '10:16:00' 
  AND "TYPE" = 'TRADE'
  ORDER BY "TIME" ASC LIMIT 3
Run Code Online (Sandbox Code Playgroud)

我已经建立了三个指数如下

Columns "DATE" DESC NULLS LAST
Columns "SECURITY" DESC NULLS LAST
Columns "TIME" DESC NULLS LAST
Run Code Online (Sandbox Code Playgroud)

我没有索引TYPE,因为它只接受两个可能值中的一个

解释分析产生以下内容

"Limit  (cost=50291.28..50291.28 rows=3 width=16) (actual time=1794484.566..1794484.567 rows=3 loops=1)"
"  ->  Sort  (cost=50291.28..50291.29 rows=4 width=16) (actual time=1794484.562..1794484.563 rows=3 loops=1)"
"        Sort Key: "TIME""
"        Sort Method:  top-N heapsort  Memory: 25kB"
"        ->  Bitmap Heap Scan on "YEAR"  (cost=48569.54..50291.24 rows=4 width=16) (actual time=1794411.662..1794484.498 rows=20 loops=1)"
"              Recheck Cond: (("SECURITY" = 'STW.AX'::bpchar) AND ("DATE" = '2010-03-01'::date))"
"              Filter: (("TIME" < '10:16:00'::time without time zone) AND ("TYPE" = 'TRADE'::bpchar))"
"              ->  BitmapAnd  (cost=48569.54..48569.54 rows=430 width=0) (actual time=1794411.249..1794411.249 rows=0 loops=1)"
"                    ->  Bitmap Index Scan on security_desc  (cost=0.00..4722.94 rows=166029 width=0) (actual time=1793917.506..1793917.506 rows=1291933 loops=1)"
"                          Index Cond: ("SECURITY" = 'STW.AX'::bpchar)"
"                    ->  Bitmap Index Scan on date_desc  (cost=0.00..43846.35 rows=2368764 width=0) (actual time=378.698..378.698 rows=2317130 loops=1)"
"                          Index Cond: ("DATE" = '2010-03-01'::date)"
"Total runtime: 1794485.224 ms"
Run Code Online (Sandbox Code Playgroud)

该数据库在Core2Quad上运行大约10亿行,在Ubuntu 64bit上运行8gig RAM.当然这个查询不应该花半个小时

Den*_*rdy 12

该数据库在Core2Quad上运行大约10亿行,在Ubuntu 64bit上运行8gig RAM.当然这个查询不应该花半个小时

由于您设置索引的方式,它需要半个小时.

您的查询没有可用于直接转到所需行的多列索引.它做了下一个最好的事情,即对几乎没有选择性的索引进行位图索引扫描,并对结果集进行排序前3.

有问题的两个索引,关于安全性和日期,分别产生1.3M和2.3M行.将它们组合在一起将会非常缓慢,因为您会随机查找超过一百万行并过滤每一行.

更糟糕的是,您的数据结构使得两个高度相关的字段(日期和时间)分别存储和操作.这会混淆查询计划程序,因为Postgres不会收集关联数据.因此,您的查询几乎总是依赖于过滤大量数据,并按照单独的标准对过滤集进行排序.

我建议进行以下更改:

  1. 更改表并添加类型的日期时间列timestamp with time zone.将日期和时间列合并到其中.

  2. 相应地删除日期和时间字段,以及它们上的索引.同时删除安全性索引.

  3. 在(安全性,日期时间)上创建索引.(并且除非您的排序条件也包含这些子句,否则不要将nulls置于最后/空值.)

  4. 如果您需要执行在日期或日期范围内对所有交易执行统计信息的查询,则可以选择在(datetime)或on(datetime,security)上添加单独的索引.

  5. 一旦完成上述操作,真空分析整个混乱.

然后,您就可以像这样重写您的查询:

SELECT "TIME", "TRADEPRICE"
  FROM "YEAR"
  WHERE '2010-03-01 00:00:00' <= "DATETIME" AND "DATETIME" < '2010-03-01 10:16:00'
  AND "SECURITY"='STW.AX' 
  AND "TYPE" = 'TRADE'
  ORDER BY "DATETIME" ASC LIMIT 3
Run Code Online (Sandbox Code Playgroud)

这将产生最优化的计划:从(安全性,日期时间)的过滤索引扫描中检索前3行,我期望(因为你有10亿行)最多需要25ms.

  • 另一个非侵入式选项是创建一个`IMMUTABLE` pl/pgsql查找`FUNCTION`,它返回连接的`DATE`和`TIME`字段.然后,使用查找"FUNCTION"创建一个`INDEX`.事实证明,这种方法很有用,你无法轻易改变架构.请务必编写查询以使用查找"FUNCTION",否则您将看不到任何好处. (4认同)