首页 > 解决方案 > Mysql索引优化使用范围之间的位置

问题描述

我有一个 mysql 表(1,612,480),其中包含以下行:

id,
origin_zip_start
origin_zip_end
destination_zip_start
destination_zip_end
zone

我添加了索引,origin_zip_start,origin_zip_end,destination_zip_start,destination_zip_end,zone因为我认为在 where 语句中使用时应该添加索引。


当我尝试使用这个查询时,它返回 500ms;而且我想不出一种聪明的方法来进行扫描。

SELECT
    `carrier`,
    `zone`,
    `service`
FROM
    `zone_charts`
WHERE (`origin_zip_start` <= 123
    AND `origin_zip_end` >= 123)
and(`destination_zip_start` <= 456
    AND `destination_zip_end` >= 456
    OR `destination_zip_start` <= 45678
    AND `destination_zip_end` >= 45678)
AND `zone` IS NOT NULL

即使它使用了我的索引,它仍然扫描 1.6m。

Describe: my_index   1603448    1.45    Using where

在这种情况下有没有添加索引的好方法?我见过很多添加索引的聪明方法,但我找不到适合我的想法。


数据库表如下所示,并显示前 3 位数字。目标 zips 有时包含 5 位数字,这就是我在查询中使用 OR 语句的原因。

origin_zip_start: OS
origin_zip_end: OE
destination_zip_start: DS
destination_zip_end: DE

OS  |  OE  |  DS  | DE  | zone
123 | 124  | 444  | 446 | 3
125 | 126  | 444  | 446 | 5
127 | 130  | 446  | 446 | 3

标签: mysqlindexing

解决方案


(目前对于评论来说太大了;我希望将其扩展为答案。)

把想法大声说出来...

正如您所发现的,“范围”是在WHERE子句中优化的麻烦。

如果每个邮政编码范围都由某人“拥有”(如“城市”)会怎样。那么 12340..12459 可能“属于”堪萨斯州的 Anytown。

现在,您可以非常有效地将 12345 变成“Anytown, Kansas”。潜在的优势是这是一个单点,而不是一个范围。这显示了 IP 地址的等效问题(和解决方案):http: //mysql.rjweb.org/doc.php/ipranges

现在,我对您的问题空间的理解变得模糊。该查询似乎在谈论将一个城市 (123) 与其他两个城市 (456 或 45678) 中的任何一个连接起来。但我很困惑——似乎 45678 包含在 456 中。

另一个困惑...您是否有多个从 123 到 456 的“运营商”?

(给我一些关于你的任务的更多见解;我也许能够更进一步、更有效地传达这个概念。)


推荐阅读