我正在尝试调试生产速度慢的查询,但在我的开发机器上运行速度很快.我的开发框有一个prod数据库的快照,它只有几天的历史,所以两个数据库的内容大致相同.
查询是:
select count(*) from big_table where search_column in ('something')
笔记:
> big_table是一个snapshot materialized view行,大约35M行,每天刷新
> search_column有一个b树索引.
> ubuntu上的prod是9.1
OS X上的> dev是9.0
查询计划
解释结果分析:
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)
开发:
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行.
虽然两个计划的结构是相同的,但是可以解释上述成本的差异,因为每个数据库中该表的行数大致相同?
膨胀
在@ bma的建议中,这里是prod和dev的“膨胀”查询的结果以及相关的表/索引:
PROD:
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
瞧,这里有区别.
我已经运行了真空分析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)
开发:
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)
最佳答案 狂野的猜测(对评论来说太长了……):由于数据分布,用于刷新mat视图的查询计划可能会非常不同,导致mat视图以完全不同的方式填充.
这最终可能会产生类似的位图索引扫描计划,但后者可以方便地访问您开发中的精选几个磁盘页面,而不是生产中的大量磁盘页面.
如果此引导对您有意义,您是否还可以发布用于实际创建/刷新mat视图的查询计划?如果它们差异很大(成本估算,计划等),请尝试在mat视图上创建聚簇索引(可能在search_column本身上),以查看它是否有任何重大差异. (这样做后别忘了分析.)