【发布时间】:2021-05-03 10:39:26
【问题描述】:
尝试优化 MySQL 查询。需要优化的原因是表增长。 目前它有大约 300K 行,未来还会更多。
表结构
CREATE TABLE `activity_log` (
`id` int(11) UNSIGNED NOT NULL,
`date_created` datetime NOT NULL,
`user_id` int(11) UNSIGNED NOT NULL,
`event_id` smallint(6) UNSIGNED NOT NULL,
`activity_by` tinyint(4) NOT NULL DEFAULT '0' COMMENT '''0'' - by client himself; ''-1'' - by admin; other - ap_user.id;',
`text` text NOT NULL,
`notes` text NOT NULL,
`ip` char(46) DEFAULT NULL
) ENGINE=Aria DEFAULT CHARSET=utf8;
ALTER TABLE `activity_log`
ADD PRIMARY KEY (`id`),
ADD KEY `client_id` (`user_id`),
ADD KEY `event_id` (`event_id`),
ADD KEY `date_created` (`date_created`),
ADD KEY `ip` (`ip`);
ALTER TABLE `activity_log` ADD FULLTEXT KEY `text` (`text`);
ALTER TABLE `activity_log`
MODIFY `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=2435463;
COMMIT;
查询需要优化:
SELECT a.id,a.activity_by,a.user_id,a.date_created,
DATE_FORMAT(a.date_created,'%e %b, %Y') as date,
DATE_FORMAT(a.date_created,'%H:%i') as time ,
a.text,a.notes,e.color,e.link_icon, u.id as user_id, u.login, r.role
FROM `activity_log` a
LEFT JOIN `ap_user` u ON a.activity_by = u.id
LEFT JOIN `ap_role` r ON u.role_id = r.id,
`activity_log_events` e
WHERE 1
AND a.event_id=e.id
AND a.text LIKE '%test tester%'
ORDER BY `date_created` DESC, `id` DESC
我已经尝试过用 FULLTEXT 替换 %LIKE% 查询
SELECT a.id,a.activity_by,a.user_id,a.date_created,
DATE_FORMAT(a.date_created,'%e %b, %Y') as date,
DATE_FORMAT(a.date_created,'%H:%i') as time ,
a.text,a.notes,e.color,e.link_icon, u.id as user_id, u.login, r.role
FROM `activity_log` a
LEFT JOIN `ap_user` u ON a.activity_by = u.id
LEFT JOIN `ap_role` r ON u.role_id = r.id,
`activity_log_events` e
WHERE 1
AND a.event_id=e.id
AND MATCH (a.text) AGAINST ('test tester*' IN BOOLEAN MODE) ORDER BY `date_created` DESC, `id` DESC
如果此信息很重要,则此查询将具有其 LIMIT 15 近似值,用于 DataProvider 和分页。
所以我添加了FULLTEXT index 并将假数据放入此表中,它有大约 100 万行。
奇怪的事情之一是like 查询为 100 万行表提供了 1300 个结果,而MATCH 查询为同一个表提供了 200_000 个结果。
首先认为这是因为表包含相同的行,因为我复制它们进行测试。那可能吗? FULLTEXT 搜索因此非常慢,like 搜索给出了不公平的结果 - 1k 而不是 200k。
这是一个特定的表格,无论如何都会包含许多类似的词,例如名称和标准短语,例如“已添加”或“已删除”。
如何优化这个%like% 查询?没有FULLTEXT可以吗?如果不是 - 我对 FULLTEXT 查询到底做错了什么?
感谢您的帮助。
【问题讨论】:
-
@RobMoll 谢谢,但这不是问题,我正在按当前表中的一个且唯一的字段搜索文本,因此在 CONCAT 中不需要。
-
AGAINST ('test tester*')在该字符串中查找 test or tester* anywhere,而like '%test tester%'正好在彼此后面查找这些字母(例如,第一个“单词”可以end 以“test”)并按此顺序。至于如何优化您的查询:尝试AGAINST ('+test +tester*' in boolean mode)至少找到两者,也许可以解决它。但总的来说,全文索引是查找稀有词的工具。如果 1kk 行中有 200k 匹配,则您要么使用了非常不幸或非常不典型的测试词/测试数据库内容,要么您可能需要重新设计您的模型。 -
Doyle 的博客有几个问题;无论如何,我认为没有太大的相关性。
-
请提供一些应该匹配的字符串和一些不应该匹配的字符串。
MATCH...AGAINST("test")将 [我认为] 匹配“测试测试人员”甚至只是“测试人员”。如果你特别想要没有后缀的“test”这个词,全文是多余的,因为它匹配“tests”、“testing”等。
标签: php mysql yii2 full-text-search sql-like