在 WHERE 子句已编入索引的情况下,如何加快此 MySQL 查询的速度?

How can I speed up this MySQL Query where the WHERE clauses are already indexed?

我有以下查询,处理时间在 300 毫秒到 450 毫秒之间。

table 大约有 30 万行,大小为 46 MB。

我创建了以下索引:

  1. Index1 - country 和 countryiso
  2. Index2 - city 和 cityabbr
  3. Index3 - city and cityabbr and country and country iso


SELECT latitude, longitude, timezone
FROM geolocate WHERE
(LCASE(country) = 'cambodia' OR LCASE(countryiso) = 'cambodia')
AND
(
(LCASE(city) = 'kaôh préab' OR LCASE(cityabbr) = 'kaôh préab')
);

300 毫秒我觉得时间太多了,但我不确定如何让它更快。

我已尝试创建单独的列索引,但无济于事。

如果有人能提供任何帮助,我将不胜感激。

假设您的 table 中的列使用 utf8 字符集及其默认排序规则 utf8_general_ci:

您不需要 LCASE() 函数调用,因为 MySQL 已经使用了不区分大小写的比较。例如,将 LCASE(country) = 'cambodia' 更改为 country = 'cambodia'

排序规则被嵌入到索引中,因此如果存在索引,这会很有效。

您的 index2 是不必要的,因为它也包含在 index3 中。

具有 OR 操作的查询往往很慢。可以使用一些技巧来加快速度。

我不知道你的索引是否正确。为此,您需要显示您的 EXPLAIN 结果和您的 table 定义。请read this note about asking good SQL questions,并注意查询性能部分。

我会就如何更改您的列定义提供建议,但您没有给我们您的 table 定义。

(O.Jones 解释了如何摆脱 LCASE;我将在给定查询的上下文中解决 OR。)

计划 A:让您的应用程序识别名称是全名还是缩写。如果您期望标准的 2 个字母 country_code,例如 KH,则检查输入的长度并构建适当的查询以避免 ORcountry_code 应该是 CHAR(2) CHARACTER SET ascii`。

B 计划:将 OR 变成 UNION。使用原始查询,您需要 UNION 中的 4 SELECTs。计划 A 后,您只需 2 个即可逃脱。

计划 C:查找 table city 的所有变体——拼写、缩写、中文等。这个 table 将映射到规范拼写主要用于table。有了这个,你就可以避免 OR for city.

方案 D:增加一个 TEXT 列,其中包含 city、cityabbrev、country、countryabbrev。以及可能的变体拼写。使用 FULLTEXT 索引此列。警告:short 'words' 存在问题;您可能应该将最小标记大小设置为 2 以捕获 country_code.