3

我有两张桌子,一张用于路线,一张用于机场。

Routes 包含刚刚超过 9000 行,我已经为每一列建立了索引。机场只有 2000 行,我也为每一列编制了索引。

当我运行此查询时,最多可能需要 35 秒才能返回 300 行:

SELECT routes.* , a1.name as origin_name, a2.name as destination_name FROM routes
LEFT JOIN airports a1 ON a1.IATA = routes.origin
LEFT JOIN airports a2 ON a2.IATA = routes.destination
WHERE routes_build.carrier = "Carrier Name"

用“DESCRIBE”运行它,我得到了以下信息,但我不能 100% 确定它告诉我什么。

id | Select Type   | Table             | Type   | possible_keys        | Key            | Key_len   | ref    | rows     | Extra
--------------------------------------------------------------------------------------------------------------------------------------
1  | SIMPLE        | routes_build      | ref    | carrier,carrier_2    | carrier        | 678       | const  | 26       | Using where
--------------------------------------------------------------------------------------------------------------------------------------
1  | SIMPLE        | a1                | ALL    | NULL                 | NULL           | NULL      | NULL   | 5389     |
--------------------------------------------------------------------------------------------------------------------------------------
1  | SIMPLE        | a2                | ALL    | NULL                 | NULL           | NULL      | NULL   | 5389     |
--------------------------------------------------------------------------------------------------------------------------------------

我能想到的唯一选择是运行两个单独的查询并将它们与 PHP 连接起来,但我无法相信这样的事情会杀死 mysql 服务器。所以像往常一样,我怀疑我在做一些愚蠢的事情。SQL 是我的第一个弱点。

4

5 回答 5

3

就个人而言,我会首先删除左连接并用内连接替换它们,因为每条路线都必须有一个起点和终点。

于 2009-06-26T15:34:25.113 回答
1
SELECT  routes.*, a1.name as origin_name, a2.name as destination_name
FROM    routes_build
LEFT JOIN
        airports a1
ON      a1.IATA = routes_build.origin
LEFT JOIN
        airports a2
ON      a2.IATA = routes_build.destination
WHERE   routes_build.carrier = "Carrier Name"

从你的EXPLAIN PLAN我可以看出你没有索引airports.IATA

您应该创建它以使查询快速工作。

名称还表明它应该是一个UNIQUE索引,因为IATA代码是唯一的。

更新:

请发布您的表格定义。发出此查询以显示它:

SHOW CREATE TABLE airports

另外我应该注意,除非您将配置设置为或更少,否则您的FULLTEXT索引IATA是无用的。ft_max_word_lenMySQL3

默认情况下,它是4.

IATA代码是3字符长,并且MySQL不使用FULLTEXT默认设置搜索这样短的单词。

于 2009-06-26T15:39:30.080 回答
1

它告诉您它没有使用索引来加入 airports 表。看看“行”列是如何如此巨大的,有 5000 多个?这就是它必须读取多少行才能回答您的查询。

我不知道为什么,因为你声称你已经索引了每一列。什么是国际航空运输协会?它是独一无二的吗?我相信如果 mysql 认为索引效率低下,它可能会忽略它。

编辑:如果 IATA 是一个唯一的字符串,也许尝试只索引它的一半?(你可以选择索引多少个字符)这可能会给mysql一个它可以使用的索引。

于 2009-06-26T15:43:31.633 回答
0

在您实施 Martin Robins 的出色建议(即从您的查询中删除该单词的每个实例LEFT)后,尝试在、和上给出routes_build复合索引。carrierorigindestination

于 2009-06-26T15:38:15.420 回答
0

这实际上取决于您要获取的信息。您可能不需要两次加入机场,也可能不需要使用左连接。此外,如果您可以搜索数字字段而不是文本字段,那也会加快速度。

那么你想获取什么?

于 2009-06-26T15:39:17.100 回答