Postgres解释计划是不同的

时间:2014-07-14 13:09:20

标签: postgresql sql-execution-plan

我在同一台服务器上运行了2个数据库。 两者都是具有相同结构但数据量不同的开发数据库。 在Linux上运行Postgres 9.2(Centos / Redhat)

我在每个数据库上运行以下SQL,但性能差异很大。

注意:每个数据库中的write_history表结构相同,并且具有相同的索引/约束。

这是SQL:

 explain analyze SELECT * FROM write_history WHERE fk_device_rw_id =
 'd2c969b8-2609-11e3-80ca-0750cff1e96c'  AND fk_write_history_status_id
 = 5  ORDER BY update_time DESC LIMIT 1 ;

每个数据库的解释计划:

DB1 - PreProd

 Limit  (cost=57902.39..57902.39 rows=1 width=103) (actual
 time=0.056..0.056 rows=0 loops=1)'   ->  Sort 
 (cost=57902.39..57908.69 rows=2520 width=103) (actual
 time=0.053..0.053 rows=0 loops=1)'
         Sort Key: update_time'
         Sort Method: quicksort  Memory: 25kB'
         ->  Bitmap Heap Scan on write_history  (cost=554.04..57889.79 rows=2520 width=103) (actual time=0.033..0.033 rows=0 loops=1)'
               Recheck Cond: (fk_device_rw_id = 'd2c969b8-2609-11e3-80ca-0750cff1e96c'::uuid)'
               Filter: (fk_write_history_status_id = 5)'
               ->  Bitmap Index Scan on idx_write_history_fk_device_rw_id  (cost=0.00..553.41 rows=24034
 width=0) (actual time=0.028..0.028 rows=0 loops=1)'
                     Index Cond: (fk_device_rw_id = 'd2c969b8-2609-11e3-80ca-0750cff1e96c'::uuid)' Total runtime: 0.112 ms'

DB2 - QA

 Limit  (cost=50865.41..50865.41 rows=1 width=108) (actual
 time=545.521..545.523 rows=1 loops=1)'   ->  Sort 
 (cost=50865.41..50916.62 rows=20484 width=108) (actual
 time=545.518..545.518 rows=1 loops=1)'
         Sort Key: update_time'
         Sort Method: top-N heapsort  Memory: 25kB'
         ->  Bitmap Heap Scan on write_history  (cost=1431.31..50762.99 rows=20484 width=108) (actual time=21.931..524.034 rows=22034
 loops=1)'
               Recheck Cond: (fk_device_rw_id = 'd2cd81a6-2609-11e3-b574-47328bfa4c38'::uuid)'
               Rows Removed by Index Recheck: 1401986'
               Filter: (fk_write_history_status_id = 5)'
               Rows Removed by Filter: 40161'
               ->  Bitmap Index Scan on idx_write_history_fk_device_rw_id  (cost=0.00..1426.19 rows=62074
 width=0) (actual time=19.167..19.167 rows=62195 loops=1)'
                     Index Cond: (fk_device_rw_id = 'd2cd81a6-2609-11e3-b574-47328bfa4c38'::uuid)' Total runtime: 545.588 ms'

所以有几个问题:

  1. "排序方法有什么区别:快速排序内存:25kB"和"排序方法:top-N heapsort内存:25kB"

  2. 可能导致总运行时间如此不同的原因是什么?

  3. 表行数:

    DB1:write_history行数:5,863,565

    DB2:write_history行数:2,670,888

    如果需要进一步的信息,请告诉我。 谢谢你的帮助。

2 个答案:

答案 0 :(得分:1)

1)两种不同的排序算法。

http://en.wikipedia.org/wiki/Quicksort

http://en.wikipedia.org/wiki/Heapsort

2)正在排序的数据量将改变决定。

从数据库理论的记忆;由于QuickSort扫描数据的顺序,QuickSort对大量数据的执行非常糟糕。如果排序需要缓存到磁盘,那就特别糟糕。堆排序比最快排序更糟糕。查询计划程序知道这一点,并将相应地更改计划。

要排序的行数大8倍。要非常小心地注意到预期要选择的行数以及表中的行数。查询计划程序使用数据的直方图来更好地了解将要选择的内容,而不仅仅是表中的行数。在DB1中它是2.5K,在DB2中它是20K

您可以通过检查结果行集是否与估算中的计数匹配来检查这些估计值是否正确。如果没有,请考虑执行ANALYZE

答案 1 :(得分:1)

排名前N的排序意味着它正在排序以支持ORDER BY ... LIMIT N,并且一旦它可以显示元组不能位于前N个,它将抛弃任何元组。切换的决定在排序过程中动态地进行前N级排序。由于那种输入元组为零,因此决定切换到它。因此报告方法的差异是影响,而不是原因;并不重视这种情况。

我认为你的关键是位图堆扫描:

(actual time=0.033..0.033 rows=0 loops=1)

(actual time=21.931..524.034 rows=22034 loops=1)

较小的数据库有很多符合条件的更多行,因此还有很多工作要做。

此外,需要完成的复核工作量:

Rows Removed by Index Recheck: 1401986

建议你将work_mem设置为一个非常小的work_mem值,这样你的位图就会溢出它。