4

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

查询是:

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

笔记:

  • big_table是一个快照物化视图,大约有 3500 万行,每天刷新一次
  • search_column有一个 b 树索引。
  • 产品在 ubuntu 上是 9.1
  • 在 OS X 上 dev 是 9.0

查询计划

结果explain analyze

产品

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)

开发

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)

prod 和 dev 两个查询的实际结果分别为 210053 和 209551 行。

尽管这两个计划的结构相同,但考虑到每个 DB 中该表的行数大致相同,如何解释上述成本的差异?

膨胀

根据@bma 的建议,以下是 prod 和 dev 的“膨胀”查询以及相关表/索引的结果:

产品

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

开发

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

瞧,这里有区别。

我已经运行vacuum analyze big_table;了,但这似乎与计数查询的运行时间没有任何显着差异。

配置

SELECT name, current_setting(name), source FROM pg_settings WHERE source NOT IN ('default', 'override');bma 建议的结果:

产品

            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)

开发

            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)
4

2 回答 2

1

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

这将花费一些时间并且会在该表运行时阻塞该表,但是这会使磁盘上的表数据按此 search_column 排序。因此,所有受search_column值限制的查询只需检索有限数量的磁盘块,甚至可能从磁盘盘片上的有限位置检索。重新索引将处理cluster.

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

于 2013-10-03T13:53:08.113 回答
1

疯狂的猜测(评论有点太长了......):可能是由于数据分布,用于刷新 mat view 的查询计划非常不同,导致 mat view 以完全不同的方式填充。

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

如果这条线索对您有意义,您是否还可以发布用于实际创建/刷新 mat 视图的查询计划?如果它们大相径庭(成本估算、计划等),请尝试在 mat 视图(可能在 search_column 本身)上创建一个聚集索引,看看它是否有任何实质性差异。(这样做后不要忘记分析。)

于 2013-10-03T10:22:57.007 回答