所以,我做了一些测试。
TL;DR
- 将国家列类型更改为
CHAR(32),重建索引,您应该会获得更好的性能。
加长版:
在 linux centos 7 上使用了 informix 12.10FC6DE(在 virtualbox 中创建的 VM)。用于 dbspace 的页面大小为 2048 字节,缓冲池为 50000 页。
创建了一个表 (tst),其行大小约为 425 字节(平均每页 4 行),包含几列。在这些列中,一个是country VARCHAR(32),另一个是static_country CHAR(32)。
用 499999 行填充表格,country 和 static_country 列均匀分布在 25 个国家/地区名称中。
创建了 2 个索引,一个在列 country (idx1_tst) 上,另一个在列 static_country (idx2_tst) 上。
表分区使用了 125000 个数据页(使用 oncheck -pT)。
索引使用了大约 1500 个页面(使用 oncheck -pT)。
A. 多次运行查询,强制进行顺序扫描(运行时间在 10 到 15 秒之间):
SELECT --+ FULL (tst)
country, COUNT(*)
FROM
tst
GROUP BY
country
DIRECTIVES FOLLOWED:
FULL ( tst )
DIRECTIVES NOT FOLLOWED:
Estimated Cost: 1415645
Estimated # of Rows Returned: 25
Temporary Files Required For: Group By
1) mydb.tst: SEQUENTIAL SCAN
Query statistics:
-----------------
Table map :
----------------------------
Internal name Table name
----------------------------
t1 tst
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t1 499999 499999 499999 00:12.17 140001
type rows_prod est_rows rows_cons time est_cost
------------------------------------------------------------
group 25 25 499999 00:13.01 1275644
B. 多次运行查询,强制对 VARCHAR(32) 类型的 country 列索引进行 INDEX SCAN(运行时间在 4m30s 和 5m 之间):
SELECT --+ INDEX (tst idx1_tst)
country, COUNT(*)
FROM
tst
GROUP BY
country
DIRECTIVES FOLLOWED:
INDEX ( tst idx1_tst )
DIRECTIVES NOT FOLLOWED:
Estimated Cost: 3462411
Estimated # of Rows Returned: 25
1) mydb.tst: INDEX PATH
(1) Index Name: mydb.idx1_tst
Index Keys: country (Serial, fragments: ALL)
Query statistics:
-----------------
Table map :
----------------------------
Internal name Table name
----------------------------
t1 tst
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t1 499999 499999 499999 04:49.71 3462411
type rows_prod est_rows rows_cons time est_cost
------------------------------------------------------------
group 25 25 499999 04:50.51 1275644
C. 多次运行查询,强制对 CHAR(32) 类型的 static_country 列索引进行 INDEX SCAN(运行时间在 2 到 3 秒之间):
SELECT --+ INDEX (tst idx2_tst)
static_country, COUNT(*)
FROM
tst
GROUP BY
static_country
DIRECTIVES FOLLOWED:
INDEX ( tst idx2_tst )
DIRECTIVES NOT FOLLOWED:
Estimated Cost: 16428
Estimated # of Rows Returned: 25
1) mydb.tst: INDEX PATH
(1) Index Name: mydb.idx2_tst
Index Keys: static_country (Key-Only) (Serial, fragments: ALL)
Query statistics:
-----------------
Table map :
----------------------------
Internal name Table name
----------------------------
t1 tst
type table rows_prod est_rows rows_scan time est_cost
-------------------------------------------------------------------
scan t1 499999 499999 499999 00:02.02 16429
type rows_prod est_rows rows_cons time est_cost
------------------------------------------------------------
group 25 25 499999 00:02.72 1277132
使用 sysmaster 数据库上的 SMI 表 sysptprof 我可以看到以下计数器(在运行之间使用 onstat -z 来重置计数器):
- 在情况 A(序列扫描)中:
- 表 tst 分区:
lockreqs 499999
isreads 125001
bufreads 500060
pagreads 117532
- 如果是 B(VARCHAR 类型列上的 INDEX SCAN):
- 表 tst 分区:
lockreqs 499999
isreads 499990
bufreads 999997
pagreads 348585
- 索引 idx1_tst 分区:
lockreqs 499999
isreads 500009
bufreads 506961
pagreads 2545
- 如果是 C(CHAR 类型列上的 INDEX SCAN):
- 索引 idx2_tst 分区:
lockreqs 499999
isreads 500000
bufreads 502879
pagreads 1440
所以,对于 SEQUENCIAL SCAN,正如我所料,只有表分区上有活动。
对于 CHAR 列上的 INDEX SCAN,只有索引分区上的活动,正如我所料(解释包含 Key-Only 指示)。
对于 VARCHAR 列上的 INDEX SCAN,表和索引分区中都有活动,这不是我所期望的(但正如费尔南多指出的那样,解释不包含 Key-Only 指示)。
我无法从 informix 中解释这种行为。但是一位同事向我指出了informix性能手册(版本12.10FC6,第10章,查询计划,访问计划)上的这个条目:
重要提示:优化器不会为 VARCHAR 选择仅键扫描
柱子。如果您想利用仅键扫描,请使用 ALTER
带有 MODIFY 子句的 TABLE 将列更改为 CHAR 数据类型。