2

阅读这篇 wiki 文章,我发现如果在 MySQL 数据库中使用带有索引列的 IN() 子句,则 SELECT 性能会被杀死。我的问题是,我怎样才能重写我的查询,以便它不会使用任何 IN() 子句,同时仍保持其功能?

我的查询是:

SELECT 
    `Route`.`route_id`, `Route`.`order`, `Route2`.`order` 
FROM 
    `routes` AS `Route` 
INNER JOIN 
    `routes` AS `Route2` 
ON `Route`.`route_id` = `Route2`.`route_id` 
WHERE 
    `Route`.`station_line_id` IN ([10 values]) AND 
    `Route2`.`station_line_id` IN ([10 values]) AND 
    `Route`.`order` <= `Route2`.`order` 
GROUP BY `
    `Route`.`station_line_id`, `Route2`.`station_line_id`, (`Route2`.`order` - `Route`.`order`)

并且我已经索引了所有列(route_id、station_line_id、station_id 和 line_id),其中 id 列是主键(该表在生成后只是只读的,所以不用担心索引所有内容)。[10 values]IN() 子句中的 以逗号分隔,例如:IN(1, 2, ..., 10).

基本上,我自己加入表路由表并将结果分组以获得所需的记录。其他联接用于检索关联数据。

性能方面,使用 InnoDB 存储引擎,我在 > 30 秒内执行了类似的查询。使用 MyISAM,我得到 >5 秒。但我相信可以更快地获取结果。我的表中有大约 450 万条记录。

4

1 回答 1

1

您将在使用“哈希索引”的此类查询中获得最佳性能。“标准”索引是 B+ 树,它允许您在 log(n) 时间内查找条目,其中 n 是表中的行数。它们还保持排序顺序,因此您可以有效地执行类似的查询... WHERE station_line_id > 14,这就是您要在Order列上使用的内容。

但是,在您的情况下,使用IN子句,您只是在寻找等价性。在这种情况下,B+ 树将不得不单独查找所有 m 个“[10 个值]”,这将花费您 m * log(n) 时间,这显然需要 5-30 秒。

哈希索引用于在恒定的时间内(非常快)查找等效条目,这不依赖于(理论上)表中的行数——即使在大表上也总是非常快。哈希索引的缺点是您不能使用它来执行类似<or的查询>,但它在等价查询中是最快的,例如您在 inIN子句中执行的查询station_line_id

编辑:特别是对于 MySQL,不幸的是,他们在任何流行的数据库引擎上都不支持 HASH 索引。如果您能够使用 MEMORY 或 HEAP 引擎,那么您可以使用 HASH 索引——无论如何,将所有内容都放在内存中可能会大大提高性能。值得一试。

于 2012-04-13T15:30:49.377 回答