H2 数据库:虽然使用了索引但查询速度很慢

Posted

技术标签:

【中文标题】H2 数据库:虽然使用了索引但查询速度很慢【英文标题】:H2 database: slow query although index is used 【发布时间】:2015-01-22 14:37:52 【问题描述】:

使用 H2 1.3.176。

1) 表定义:

CREATE TABLE TEST(ID BIGINT PRIMARY KEY, ACCOUNT BIGINT, TXID BIGINT); 

2) 向表中插入值:

INSERT INTO TEST SELECT X, RAND()*100, X FROM SYSTEM_RANGE(1, 1000000)

3) 为我的查询创建索引:

CREATE Unique INDEX IDX_TEST_ACCOUNT_TXID ON `test` (account, txId DESC);

4) 执行以下查询:

explain analyze
select txid from test where account=22 AND txid<9999999 order by txid desc limit 25

我得到以下执行计划:

SELECT
    TXID
FROM PUBLIC.TEST
    /* PUBLIC.IDX_TEST_ACCOUNT_TXID: ACCOUNT = 22
        AND TXID < 9999999
     */
    /* scanCount: 9867 */
WHERE (ACCOUNT = 22)
    AND (TXID < 9999999)
ORDER BY 1 DESC
LIMIT 25
/*
TEST.IDX_TEST_ACCOUNT_TXID read: 103
*/

问题:为什么H2需要扫描整个索引?我期望扫描计数为 25,因为索引中的 txid 应该已经按降序排列,所以一旦 H2 在索引的 account=22 分支中,它应该能够读取接下来的 25 个条目。如果表中有数百万个条目,这将导致查询缓慢。即使 H2 必须在索引中搜索第一个匹配条目,我也希望这是一个 O(log(N)) 算法而不是扫描。 如果我在没有列帐户的情况下执行相同的操作(意味着表只包含 id 和 txid),那么 txid 上的降序索引确实会导致扫描计数为 25(使用查询“select txid from test where txid

【问题讨论】:

【参考方案1】:

我浏览了 h2 源代码,发现出了什么问题:

在准备执行查询的过程中,h2 尝试确定它是否可以使用索引对结果集进行排序和限制。由于第一个索引列(account)不在order by子句中,所以h2认为它不能使用索引。这导致 h2 扫描整个索引以获取所有行,然后对结果集进行排序和限制。这是令人惊讶的,因为帐户条件是“相等”条件,因此 h2 应该意识到它确实可以使用索引来排序和限制结果集。 解决方案是在 order by 子句中提供 account 列。因此查询应该是:

select txid from test where account=22 AND txid<9999999 order by account, txid desc limit 25

我得到了预期的执行计划

SELECT
    TXID
FROM PUBLIC.TEST
    /* PUBLIC.IDX_TEST_ACCOUNT_TXID: ACCOUNT = 22
        AND TXID < 9999999
     */
    /* scanCount: 25 */
WHERE (ACCOUNT = 22)
    AND (TXID < 9999999)
ORDER BY =ACCOUNT, 1 DESC
LIMIT 25
/* index sorted */

它的扫描计数只有 25 :)

【讨论】:

以上是关于H2 数据库:虽然使用了索引但查询速度很慢的主要内容,如果未能解决你的问题,请参考以下文章

我mysql数据查询的数据过多,查询很慢,大家说用索引,可是没有接触有索引。求实例

mysql+springboot+jpa查询几十万条数据很慢 如何解决?

一个SQL有时执行速度很快有时很慢,请问处理思路

mysql 查询的时候加了索引 查询还是很慢怎么办

mysql全文索引 很慢,速度不如like的百分之一

mysql全文索引 很慢,速度不如like的百分之一