我有以下测试用例:
CREATE SCHEMA IF NOT EXISTS long;
SET search_path TO long,pg_temp,pg_catalog;
CREATE TABLE long WITH (autovacuum_enabled=off) AS
SELECT id, (random()*1000)::int AS key, random() AS value1, random() AS value2,
repeat((random()*9)::int::text, 312) AS long
FROM generate_series(1,10000000) id;
CREATE INDEX i_long_value1 ON long (value1);
CREATE INDEX i_long_wo ON long(key,value2 DESC);
VACUUM ANALYZE long;
现在,如果我解释以下查询:
SELECT * FROM long WHERE key=5 AND value1 BETWEEN 0.5 AND 0.6 ORDER BY value2 DESC;
我总是得到以下计划。这很奇怪,因为我有一个匹配的索引i_long_wo
。所以我使用:SET enable_bitmapscan TO off;
这导致了更好的计划。这在我尝试过的所有 PG 实例(win64、HP-UX、MacOS)上都是可重现的,而不仅仅是在 9.4beta2 上。此外,在查看计划之前,我已经多次运行这些查询,以确保缓存所有信息,您可以检查Buffers: shared hit
所提供计划中的条目。
我正在运行(在 MacOS 上的 9.1-9.4b2 上也观察到相同的效果):
postgres=# SELECT version();
version
----------------------------------------------------------------
PostgreSQL 9.4beta2, compiled by Visual C++ build 1800, 64-bit
postgres=# SELECT name,setting,unit,source FROM pg_settings
WHERE NOT source IN ('default','override');
name | setting | unit | source
------------------------------+--------------------+------+----------------------
application_name | psql | | client
bgwriter_delay | 50 | ms | configuration file
bgwriter_lru_maxpages | 350 | | configuration file
checkpoint_completion_target | 0.9 | | configuration file
checkpoint_segments | 100 | | configuration file
client_encoding | WIN1252 | | client
DateStyle | ISO, MDY | | configuration file
default_text_search_config | pg_catalog.english | | configuration file
dynamic_shared_memory_type | windows | | configuration file
effective_cache_size | 524288 | 8kB | configuration file
lc_messages | C | | configuration file
lc_monetary | C | | configuration file
lc_numeric | C | | configuration file
lc_time | C | | configuration file
listen_addresses | * | | configuration file
log_destination | stderr | | configuration file
log_line_prefix | %t | | configuration file
log_timezone | Europe/Helsinki | | configuration file
logging_collector | on | | configuration file
max_connections | 100 | | configuration file
max_stack_depth | 2048 | kB | environment variable
port | 5432 | | configuration file
shared_buffers | 131072 | 8kB | configuration file
TimeZone | Europe/Helsinki | | configuration file
wal_buffers | 2048 | 8kB | configuration file
work_mem | 16384 | kB | configuration file
(26 rows)
Windows 实例正在使用来自 EDB 的 9.4beta2 安装程序,我会尽快更新编译细节。用于构建 MacOS 实例的配置:
CONFIGURE = '--prefix=/usr/local/Cellar/postgresql-9.4/9.4beta2' '--enable-dtrace' \
'--with-bonjour' '--with-gssapi' '--with-ldap' '--with-libxml' \
'--with-libxslt' '--with-openssl' '--with-uuid=e2fs' '--with-pam' \
'--with-perl' '--with-python' '--with-tcl' \
'CC=/usr/bin/clang' \
'CFLAGS=-Os -w -pipe -march=native -mmacosx-version-min=10.9' \
'LDFLAGS=-L/usr/local/opt/readline/lib -L/usr/local/opt/e2fsprogs/lib \
-L/usr/local/opt/gettext/lib -L/usr/local/lib \
-Wl,-headerpad_max_install_names' \
'CPPFLAGS=-I/usr/local/opt/readline/include -I/usr/local/opt/e2fsprogs/include \
-I/usr/local/opt/gettext/include'
LIBS = -lpgcommon -lpgport -lxslt -lxml2 -lpam -lssl -lcrypto -lgssapi_krb5 \
-lz -lreadline -lm
所以我想知道 — 为什么 BitmapIndexScan 得到更好的估计?
我从 Tom Lane(很老)那里看到了这篇文章,据我所知,推荐的方法是调整*_cost
参数。但问题是——成本受页面数量的影响更大,这可以从 PostgreSQL 在执行期间接触的缓冲区数量看出,它们对于两个计划都具有可比性,并且高于返回的记录数量。因此,调整random_page_cost
降低了两个计划的成本,而 IndexScan 永远不会赢。
我尝试增加cpu_index_tuple_cost
,但我不得不将其提高0.02
到使 planner 停止使用BitmapAnd
。在此设置中,BitmapIndexScan varian 看起来好多了,但仍然不如 IndexScan。
是否可以让规划器在这里为 IndexScan 提供更好的估计?