2013-10-03 101 views
4

我试图调试生产速度慢,但在我的开发机器上速度很快的查询。我的开发箱有一个只有几天的prod数据库的快照,所以两个数据库的内容大致相同。Postgresql查询计划差异

查询是:

select count(*) from big_table where search_column in ('something') 

注:

  • big_tablesnapshot materialized view约35M行,并每天
  • search_column刷新有一个B树索引。
  • PROD是9.1 ubuntu上
  • dev为9.0在OS X

查询计划

explain analyze结果:

PROD

QUERY PLAN                      
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Aggregate (cost=1119843.20..1119843.21 rows=1 width=0) (actual time=467388.276..467388.278 rows=1 loops=1) 
    -> Bitmap Heap Scan on big_table (cost=10432.55..1118804.45 rows=415497 width=0) (actual time=116891.126..466949.331 rows=210053 loops=1) 
     Recheck Cond: ((search_column)::text = 'something'::text) 
     -> Bitmap Index Scan on big_table_search_column_index (cost=0.00..10328.68 rows=415497 width=0) (actual time=8467.901..8467.901 rows=337164 loops=1) 
       Index Cond: ((search_column)::text = 'something'::text) 
Total runtime: 467389.534 ms 
(6 rows) 

dev

QUERY PLAN                     
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
Aggregate (cost=524011.38..524011.39 rows=1 width=0) (actual time=209.852..209.852 rows=1 loops=1) 
    -> Bitmap Heap Scan on big_table (cost=5131.43..523531.22 rows=192064 width=0) (actual time=33.792..194.730 rows=209551 loops=1) 
     Recheck Cond: ((search_column)::text = 'something'::text) 
     -> Bitmap Index Scan on big_table_search_column_index (cost=0.00..5083.42 rows=192064 width=0) (actual time=27.568..27.568 rows=209551 loops=1) 
       Index Cond: ((search_column)::text = 'something'::text) 
Total runtime: 209.938 ms 
(6 rows) 

和两个查询的督促和开发的实际结果是210053个209551行,分别。

尽管两个计划的结构是相同的,但考虑到每个数据库中的表中的行数大致相同,哪些可能解释上述成本的差异?

鼓胀症

在@ BMA的建议,这里的 “膨胀” 查询的督促和开发以及相关的表/索引结果:

督促

current_database | schemaname |   tablename   | tbloat | wastedbytes |        iname        | ibloat | wastedibytes 
------------------+------------+---------------------------------+--------+-------------+---------------------------------------------------------------+--------+-------------- 
my_db   | public  | big_table      | 1.6 | 7965433856 | big_table_search_column_index         | 0.1 |   0 

dev

current_database | schemaname |   tablename   | tbloat | wastedbytes |        iname        | ibloat | wastedibytes 
------------------+------------+---------------------------------+--------+-------------+---------------------------------------------------------------+--------+-------------- 
my_db   | public  | big_table      | 0.8 |   0 | big_table_search_column_index         | 0.1 |   0 

Voila,这里有区别。

我运行了vacuum analyze big_table;但似乎没有任何显着不同的计数查询的运行时间。

配置 的 SELECT name, current_setting(name), source FROM pg_settings WHERE source NOT IN ('default', 'override');

结果如由BMA建议:

PROD

  name   |   current_setting   |  source   
----------------------------+----------------------------------+---------------------- 
application_name   | psql        | client 
DateStyle     | ISO, MDY       | configuration file 
default_text_search_config | pg_catalog.english    | configuration file 
effective_cache_size  | 6GB        | configuration file 
external_pid_file   | /var/run/postgresql/9.1-main.pid | configuration file 
listen_addresses   | *        | configuration file 
log_line_prefix   | %t        | configuration file 
log_timezone    | localtime      | environment variable 
max_connections   | 100        | configuration file 
max_stack_depth   | 2MB        | environment variable 
port      | 5432        | configuration file 
shared_buffers    | 2GB        | configuration file 
ssl      | on        | configuration file 
TimeZone     | localtime      | environment variable 
unix_socket_directory  | /var/run/postgresql    | configuration file 
(15 rows) 

dev的

  name   |  current_setting  |  source   
----------------------------+-------------------------+---------------------- 
application_name   | psql     | client 
DateStyle     | ISO, MDY    | configuration file 
default_text_search_config | pg_catalog.english  | configuration file 
effective_cache_size  | 4GB      | configuration file 
lc_messages    | en_US     | configuration file 
lc_monetary    | en_US     | configuration file 
lc_numeric     | en_US     | configuration file 
lc_time     | en_US     | configuration file 
listen_addresses   | *      | configuration file 
log_destination   | syslog     | configuration file 
log_directory    | ../var     | configuration file 
log_filename    | postgresql-%Y-%m-%d.log | configuration file 
log_line_prefix   | %t      | configuration file 
log_statement    | all      | configuration file 
log_timezone    | Australia/Hobart  | command line 
logging_collector   | on      | configuration file 
maintenance_work_mem  | 512MB     | configuration file 
max_connections   | 50      | configuration file 
max_stack_depth   | 2MB      | environment variable 
shared_buffers    | 2GB      | configuration file 
ssl      | off      | configuration file 
synchronous_commit   | off      | configuration file 
TimeZone     | Australia/Hobart  | command line 
timezone_abbreviations  | Default     | command line 
work_mem     | 100MB     | configuration file 
(25 rows) 
+2

您是否在测试之前在生产数据库上运行“ANALYZE”?此外,开发版本可能处于最佳状态:数据在磁盘上都是连续的,生产(假设正常的UPDATE/DELETE用法)很可能不是。另外:检查膨胀:http://wiki.postgresql.org/wiki/Show_database_bloat,并显示服务器之间是否有任何配置设置不同: SELECT name,current_setting(name),source FROM pg_settings WHERE source NOT IN('default','override'); – bma

+0

重新分析:有一个为数据库运行的autovacuum进程 - 如何检查是否运行ANALYZE? –

+0

重新更新/删除 - 请参阅关于作为物化视图的表格的补充说明 - 我认为这意味着在两个环境中,连续性方面的结果会非常相似? –

回答

1

野生客串s(评论太长)...:可能是因为数据分布导致用于刷新mat视图的查询计划非常不同,导致mat视图以完全不同的方式填充。

这可能会最终导致类似的位图索引扫描计划,但后者可以方便地访问您的devel安装中选定的几个磁盘页面,而不是大量的生产。

如果此引导对您有意义,您是否也可以发布用于实际创建/刷新垫视图的查询计划?如果他们广泛不同(成本估算,计划等),尝试在mat视图上创建聚簇索引(可能在search_column本身),以查看它是否有任何实质性差异。 (不要忘记在这样做后分析。)

1

如果您对此物化视图表的大多数查询都受到search_column的限制,我建议在刷新后运行cluster big_table using big_table_search_column_index; reindex big_table;

这将需要一些时间,并会在运行时阻止此表,但这会使磁盘上的表数据按此search_column排序。所以,所有查询限制为search_column值只需要检索有限数量的磁盘块,甚至可能从磁盘盘片上的有限位置。在cluster之后,重新索引会照顾可能的指数膨胀。

我认为你的开发计算机有一个SSD驱动器,它非常擅长从分散的位置检索数据。在生产中,你可能有经典的旋转磁盘或磁盘,这是非常可怕的。它也是最近创建的,因此没有膨胀(删除数据后留下空洞)。我认为这会导致几个数量级的放缓。

+0

这是一个合理的建议 - 但我应该注意'search_column'不是唯一索引的列,所以通过集群可以加快速度,但会牺牲其他搜索。是否有可能得到衡量表是如何基于索引“聚集”的,这样我就不必修改生产数据库了? –

+0

Re SSD,我的机器绝对有传统的磁性硬盘。 –