在 WHERE SQL 语句中,列的顺序是否重要?

4

我正在处理一个有很多索引的系统。一些索引比其他索引更简单,比如INT、VARCHAR、DATETIME以及在某些情况下ENUMS(可能有5~25个变化)。

WHERE条件的顺序是否重要?换句话说,将更容易搜索的列放在前面是否会增加速度/性能?

例如,我们有这样一张表:

CREATE TABLE IF NOT EXISTS `example_table` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `user_id` int(11) unsigned NOT NULL, -- 1 ~ 4,294,967,295 (non unique)
  `type_id` int(11) unsigned NOT NULL, -- (Enum with 15 values)
  `name` VARCHAR(255) NOT NULL, -- alphanumeric 
  `boolean_value` tinyInt(1) DEFAULT 0, -- only 0 or 1
  `created_date` DATETIME NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE INDEX `example_table_user_id_index` ON `example_table` (`user_id`);
CREATE INDEX `example_table_type_id_index` ON `example_table` (`type_id`);
CREATE INDEX `example_table_name_index` ON `example_table` (`name`);
CREATE INDEX `example_table_boolean_value_index` ON `example_table` (`boolean_value`);
CREATE INDEX `example_table_created_date_index` ON `example_table` (`created_date`)

我们要搜索返回最少结果的列,这样下一个条件需要查找的列就会更少,这种说法正确吗?

例如,以下语句是否会产生不同的性能结果?

1. SELECT id FROM example_table WHERE boolean_value = ? AND user_id = ? AND type_id = ? LIMIT 1000
2. SELECT id FROM example_table WHERE type_id = ? AND user_id = ? AND boolean_value = ? LIMIT 1000
3. SELECT id FROM example_table WHERE user_id = ? AND type_id = ? AND boolean_value = ? LIMIT 1000
2个回答

5
“WHERE”子句的顺序是否重要?换句话说,将易于搜索的列放在前面是否会增加速度/性能?
简短回答:不重要。
更长回答:SQL是一种声明性语言而非过程性语言。这是我们大多数开发人员经常处理的唯一声明性语言。服务器软件具有查询规划模块,使用各种方案来确定从每个查询获取结果集的最可能和最有效的方法。即使是相同的查询和不同的数据,查询计划也可能有所不同。因此,我们告诉它我们想要什么,而不是如何得到它。
有时需要调整索引或重构查询以获得良好的性能。您可以在标记中阅读有关此内容的信息。但是重构永远不像更改WHERE子句中术语的顺序那样简单。

而且,专业提示:很多单列索引通常不是一个好主意。索引需要根据正在使用的查询形状进行设计。阅读Marcus Winands的这本电子书:https://use-the-index-luke.com


2
(见OJones对你实际问题的回答。现在开始优化查询。)
这些查询的优化方式完全一样:
1. SELECT id FROM example_table
     WHERE boolean_value = ?
       AND user_id = ?
       AND type_id = ? LIMIT 1000

2. SELECT id FROM example_table
     WHERE type_id = ?
       AND user_id = ?
       AND boolean_value = ? LIMIT 1000

3. SELECT id FROM example_table
     WHERE user_id = ?
       AND type_id = ?
       AND boolean_value = ? LIMIT 1000

但最优索引应该是一种由3列("复合")组成的索引,例如:

INDEX(boolean_value, type_id, user_id)

在这个例子中,索引中的顺序不会影响结果。

您的单列索引将无法满足需求。


非常感谢您指出这一点。我之前并不知道。如果我将这些索引合并在一起,那么只使用1或2列进行where搜索是否仍然可以正常工作? - Trevor Wood
1
只需要前1或2个索引。也就是说,复合索引(如INDEX(a, b, c))将有助于大多数涉及a、b、c或a、b或a的WHERE子句。但对于其他任何组合都没有那么有用。请参阅我的Index Cookbook - Rick James
啊,我明白了!谢谢。顺便问一下关于这个话题的另一个问题,如果一行中有一个非索引列更新了,它是否仍会重新索引该行?我认为不会。 - Trevor Wood
1
@TrevorWood - 确定。"...更新一个_column_的..."(注意"行"与"列"的区别)。索引的结构类似于带有被索引的列和PRIMARY KEY列的B+树。这样,它可以通过主键进行第二次查找以获取其余的列。 - Rick James
明白了,谢谢你澄清。 - Trevor Wood

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接