MySql 缓慢的请求时间

MySql Slow Request Time

我有一台非常好的电脑,我想知道为什么向我的 table.

提出一个非常简单的请求需要这么长时间

我的电脑:

1:我的 table 有 531 732 行(这不是很多行)和 39 列

我的table有以下索引

当我进行以下查询时,需要 66.016 秒 才能得到响应:

SELECT from_unixtime(TmiSentTs/1000,'%Y/%m/%d  %H:%i:%s'),
  DisplayName, message 
FROM MY_TABLE 
WHERE displayname LIKE '%ab%'
ORDER BY TmiSentTs DESC;

我认为这不正常。

我试过:

  1. 将我的 innodb_write_io_threads 从 4 更改为 32
  2. 将我的 innodb_read_io_threads 从 4 更改为 32

但是 none 这行得通,我有另一个 table(在另一个数据库中)有 37 325 332 行,类似的查询需要 2 秒。

编辑: 经过一番研究,我发现这

SELECT * FROM pepegaclapwr.twitchmessages where instr('aa',username)<>0;

SELECT * FROM pepegaclapwr.twitchmessages where username like '%aa%';

同样的结果

displayname 列上的索引无助于此查询。任何在您要搜索的模式开头带有通配符的 LIKE 条件都不能使用索引,因此它必然会执行 table-scan.

想想电话簿。如果我要你查找以“T”开头的姓氏,那很容易,因为这本书是按姓氏排序的。但是,如果我要求您查找“T”是第 4 个字母(或第一个字母之后的任何字母)的名称,那么这本书已排序这一事实无济于事。你还是要一页一页地看全书才能找到我要的名字。

要优化您上面显示的那种查询,您可能会发现使用全文索引更容易,但这仅适用于搜索整个单词的情况。看起来您正在搜索其中某处包含“ab”的任何字符串。这不是一个完整的单词,因此全文索引也无济于事。

在这种情况下,您唯一的解决方案是向 table 添加另一列以指示该行是否包含“ab”,然后索引该列。在MySQL 5.7 及更高版本中,您可以根据表达式创建虚拟列。

ALTER TABLE MyTable
  ADD COLUMN displayname_ab TINYINT NOT NULL AS (displayname LIKE '%ab%'),
  ADD INDEX (displayname_ab);

然后搜索:

SELECT ... FROM MyTable WHERE displayname_ab = true;

在MySQL8.0中你甚至不需要做一个虚拟列,你可以直接从现有列上的表达式做一个表达式索引:

ALTER TABLE MyTable
  ADD INDEX ((displayname LIKE '%ab%'));

然后,如果您使用完全相同的表达式进行搜索,它将使用索引:

SELECT ... FROM MyTable WHERE displayname LIKE '%ab%';

但这会将您需要的字符串修复到虚拟列定义中。如果您明天需要搜索“cd”或任何其他模式,这将无济于事。