1

我有两张桌子;一个有 50 条记录并包含一些城市名称,另一个有 3173958 条记录并具有城市到国家/地区代码信息:

+---------+-----------+
| country | city      |
+---------+-----------+
| gb      | sapiston  |
| gb      | sapperton |
| gb      | sarclet   |
| gb      | sarnau    |
| gb      | sarnau    |
+---------+-----------+

大表在city字段上建立索引,但此查询大约需要5 分钟才能执行:

SELECT small.* , c2c.country FROM small LEFT JOIN c2c ON ( lower( small.city ) = lower( c2c.city ) );

问题是什么?
我怎样才能让它更快?

4

2 回答 2

3

为了利用索引,您应该将city较低格式的值存储在同一列或不同的索引列中,因为在查询中应用较低的函数不能利用索引。

SELECT small.* , c2c.country 
FROM small 
     LEFT JOIN c2c 
         ON small.city = c2c.city;

还要在表上添加以下索引和覆盖索引以获得更好的性能:

ALTER TABLE small ADD KEY ix1(city);
ALTER TABLE c2c ADD KEY ix1(city, country);

添加上述索引后,使用EXPLAIN检查查询执行计划

于 2012-09-10T09:08:08.257 回答
2

在 WHERE 子句中对列名使用函数时,不能使用索引;因为 MySQL 必须先获取所有行的计算值,然后才能进行比较。相等比较通常不区分大小写(取决于列排序规则),因此您可以安全地省略 LOWER 函数。这是修改后的查询:

SELECT small.*, c2c.country
FROM small
LEFT JOIN c2c ON small.city = c2c.city

接下来,您应该在 上添加一个覆盖索引c2c。索引应在(city, country). 这样,MySQL 就不必查看表来检索国家/地区名称。它将在加入时查看索引,同时它可以从同一索引city中获取列。country

接下来,small.*仅更改为您需要的列。

接下来,small.city如果您还没有这样做,则创建一个索引 - 或者 - 如果您发现您只需要表中的两/三列,small然后创建一个覆盖索引。例如,如果您正在选择small.somecolumn(并small.city在 WHERE/ON 子句中使用)为(city, somecolumn).

最后,确保city两个表中的列具有相同的数据类型、长度,最重要的是排序规则。当排序规则不同时,MySQL 必须在比较之前转换排序规则,这可能会减慢查询速度。

于 2012-09-10T09:17:31.867 回答