优化 MySQL 全文查询

Optimising a MySQL Full-Text Query

我有 table 个医疗诊断代码,用户可以根据这些代码执行关键字搜索。我有一列描述性文本以及一列同义词,两者都被考虑在内。结果以自动建议的格式显示,当前的查询实施速度太慢,无法部署:

SELECT
   ID AS data, CONCAT('[', ICD10, '] ', description) AS value,
   MAX(MATCH(description) AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) +
      (MATCH(synonyms) AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) * 0.5)) AS relevance
FROM Code
WHERE
   (MATCH(description) AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) OR
    MATCH(synonyms) AGAINST ("fracture forearm current init oth" IN BOOLEAN MODE)) AND
   isPCS = 0 AND
   isEnabled = 1 AND
   ICD10 IS NOT NULL AND
   description IS NOT NULL
GROUP BY ID
ORDER BY relevance DESC
LIMIT 100

table 中有约 170K 行,尽管后四个静态约束将其减少到约 94K 行,其中约 16K 行具有同义词。一个典型的查询在我的桌面 (i7-4770K) 上需要 0.45 秒,在我们的开发服务器(低端 Xeon)上大约需要 0.75 秒。删除 ORDER BY 关键字将其分别减少到 0.02 和 0.05 秒。

我原以为与全文搜索相比,对结果进行排序是微不足道的,但事实并非如此。我错过了明显的低效率吗?

我也在研究最终在 Lucene/Solr 之上重建此功能(opinions/suggestions 欢迎),但我想更好地理解此行为,并优化过渡解决方案也不会造成伤害。

如果您 order by relevance limit 100,这意味着 MySQL 必须找到所有符合您条件的行,评估您的 relevance 公式,进行文件排序,然后取其中的前 100 行.

如果您不排序,则意味着MySQL必须找到符合条件的任意100行,并且可以在那里停止执行。

所以不是找到结果后的文件排序导致速度变慢,而是必须在执行文件排序之前找到所有结果(并且可能有超过 100 行至少有一些你要找的词)。

但实际上您可以在此处使用优化:在两个列上一起使用全文索引:

CREATE FULLTEXT INDEX idxft_Code_descr_syn ON Code (description, synonyms);

然后直接在两列一起搜索,直接按全文相关度排序,不用重新计算:

SELECT
   ID AS data, CONCAT('[', ICD10, '] ', description) AS value,
   MATCH(description, synonyms) 
     AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) AS relevance
FROM Code
WHERE
  MATCH(description, synonyms) 
    AGAINST("fracture forearm current init oth" IN BOOLEAN MODE) AND
  isPCS = 0 AND
  isEnabled = 1 AND
  ICD10 IS NOT NULL AND
  description IS NOT NULL
ORDER BY relevance
LIMIT 100

与当前订单相比,这会略微改变您的相关性,因为它不会对 synomym 列和 description 列进行不同的加权,但是由于结果已经针对它们自己的单项进行了标准化列,你目前的体重可能无论如何都没有达到预期的效果。

order by relevance 仍然需要完整的 table 搜索,但是由于全文索引的工作方式(它们应该按相关性排序),您可能会得到一个下降的 speedbump它的(尽管你提到的任何一个专门的搜索引擎都会比通用的 MySQL 更快。如果它们对于 170k 行是必要的,你可以测试。更多的 RAM 有时也值得一试。但那是一个完全不同的话题。)