【问题标题】:How to index a MySQL InnoDB table to query with select ... where key in ( some values here)?如何索引 MySQL InnoDB 表以使用 select ... where key in ( some values here) 查询?
【发布时间】:2018-12-28 20:44:54
【问题描述】:

我有一个 mariadb 10.3 服务器,以及下表(使用 InnoDB 存储引擎):

create table if not exists token (
   `token` bigint unsigned not null,
    `uid` smallint unsigned not null default 0,
    `nham` int default 0,
    `nspam` int default 0,
    `timestamp` int unsigned default 0
) Engine=InnoDB;

create index token_idx1 on token(token);
create index token_idx2 on token(uid);

令牌表有大约 900k 行,我想在 IN ( ) 子句中使用 2-300 个数字执行以下查询:

select token, nham, nspam from token where token in (1,2,3,4,...);

现在的问题是:查询执行得很慢,它不会使用token_idx1

+--------+-------------+--------+------+------------- --+------------+---------+--------+--------+------- ------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +--------+-------------+--------+------+------------- --+------------+---------+--------+--------+------- ------+ | 1 |简单 |令牌 |参考 | token_idx1 | token_idx1 | 2 |常量 | 837534 |使用位置 | +--------+-------------+--------+------+------------- --+------------+---------+--------+--------+------- ------+

由于对令牌列进行了索引,我很惊讶 explain select 说优化器对 token_idx1 不感兴趣(并且查询需要很长时间,由于全表扫描,大约需要 30 秒)。

如何解决这个问题?我知道我可以在查询中使用 USE INDEX(token_idx1),但我会在没有这种 hack 的情况下解决它。

【问题讨论】:

  • 我无法想象包含 300 个元素的 in 语句会很快。你能把这些放到一个表中,然后用一个连接代替吗?
  • 不确定这是否有帮助,但我对我的一张表进行了一些测试,该表在列上有类似的索引。我只测试了 IN 子句,但得到了有趣的结果。当我使用只有有效匹配的列表时,它运行得非常快,但是当我输入无效时,它似乎扫描了整个表。 EXPLAIN 验证了这种行为。
  • 出了点问题——key_len = 2,但tokenBIGINT UNSIGNED(8 个字节)。请验证CREATE TABLE、索引和说明。
  • 你真的需要一个PRIMARY KEY 在桌子上。
  • 很遗憾,我无法将这 300 个项目放在单独的表中。如果该列被索引(原样),那么我希望即使有 300 个项目的查询也会非常快。请参阅下面的解决方案。

标签: mysql select mariadb innodb explain


【解决方案1】:

解决方法是重写查询。因此,虽然这样的查询会降低性能:

select token, nham, nspam from token where token in (1,2,3,4,...);

以下查询应该是快速的(即使表中不存在某些标记值):

从 token=1 或 token=2 或 token=3 或 ... 的 token 中选择 token、nham、nspam;

所以问题解决了,虽然我仍然不明白为什么优化器在第一次查询时遇到困难。

无论如何,感谢您的所有想法、想法和贡献,使我找到了解决方法。

【讨论】:

  • 该表有大约 8-900k 条记录。通常我一次搜索几百个标记,也许我会得到其中的一半(即表中不存在其他标记)。
  • 我之所以问,是因为我看到很多关于慢查询的问题,但作者忘记了返回几十万条记录很慢,原因有很多:) 只是一个提示,我不知道你是否知道不管它与否:EXPLAIN 还有EXPLAIN EXTENDEDprofiling。对于分析:SET PROFILING = 1; SELECT ... (your query here); SHOW PROFILE FOR QUERY 1; SET PROFILING = 0;。它往往有助于追踪服务器的哪一部分可能是瓶颈。
【解决方案2】:

删除现有索引 token_idx1 并使用

重新创建
CREATE INDEX token_idx1 ON token(token) USING BTREE;
CREATE INDEX token_idx2 ON token(uid) USING BTREE;

【讨论】:

  • 你能解释一下为什么这会有所帮助吗?
  • 不幸的是它没有帮助,因为索引类型已经是 BTREE
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-18
  • 2016-06-02
相关资源
最近更新 更多