0

在一份SELECT声明中:

SELECT name 
FROM users 
WHERE address IN (addr_a, addr_b, addr_c, ...);

我们知道它将选择所有地址在 (addr_a, addr_b, addr_c, ...) 中的人的姓名。但我想知道执行此语句时它实际上做了什么。

例如,它是否搜索表中的每个元素以检查其地址是否在 (addr_a, ...) 中?

如果addr_a,addr_b太长,是否会减慢搜索过程?

有没有关于这些东西的材料可以推荐?

编辑:我没有指定 RDBMS,因为我想知道尽可能多的 SQL 实现。

再次编辑:在这里我得到了关于 MySQL 和 SQL Server 的答案,我接受了“SQL Server”,因为它是一个详细的答案。欢迎更多关于其他 RDBMS 的答案。

4

3 回答 3

3

由于您没有指定您的问题是关于哪个 RDBMS,所以我将编写它在 SQL Server 上的工作原理,尝试稍微简化它并避免很多技术性问题。在不同的系统上它可能相同或非常相似,但也可能完全不同。

SQL Server 将如何处理您的查询

`SELECT name FROM users WHERE address IN (addr_a, addr_b, addr_c, ...);`

几乎完全取决于您在表上拥有什么样的索引。这里有3个基本场景:

场景 1(良好的索引)

如果您有所谓的Covering Index,这意味着列上的 PK 或聚集索引或包含address的非聚集索引,SQL Server 将执行名为. 这意味着它将遍历索引的树结构并快速查明您需要的确切行(或发现它不存在)。由于列也包含在索引中,因此它将读取它并从那里直接返回。addressnameIndex Seekname

场景 2(不太好的索引)

当您在address不包括 column的 column 上有索引时就是这种情况name。您可能会经常发现这类索引(仅在一列上),但您很快就会发现它们大部分时间都毫无用处。您在这里希望 SQL Server 通过您的索引结构(搜索)并快速找到您的地址所在的行。但是,由于列name现在不存在,它只能获取行实际所在的 rowID(或 PK),因此它将为返回的每一行额外读取另一个索引或表以查找您的行并检索名称。由于这需要比方案 1 多 3 倍的阅读量,因此 SQL Server 通常不会决定只遍历表的所有行而不是使用索引更便宜。这在场景 3 中进行了解释。

场景 3(无可用索引)

如果您根本没有索引或列地址上没有索引,则会发生这种情况。简单地说,SQL Server 会遍历所有行并检查每一行是否符合您的条件。这被称为Index Scan(或者Table Scan如果根本没有索引)。通常是最坏的情况,而且最慢。

希望这有助于澄清一些事情。

至于关于长弦减速的另一个子问题——这种情况的答案是“可能不多”。当 SQl Server 比较两个字符串时,它会逐个字符地进行比较,因此如果两个字符串的首字母不同,它将不会进一步检查。但是,如果您在字符串的开头放置一个通配符 %,即:WHERE address LIKE '%addr_a'SQL Server 将不得不检查列中每个字符串的每个字符,因此工作速度会慢得多。

于 2013-03-29T09:52:03.220 回答
2

文档准确地解释了它的作用。

如果所有值都是常量,则根据 expr 的类型对它们进行评估并排序。然后使用二进制搜索完成对项目的搜索。

因此,参数的顺序实际上并不重要,因为 MySQL 无论如何都会对它们进行排序以进行比较。

于 2013-03-29T05:47:29.557 回答
1

@Xu:为选择查询创建一个执行计划,并根据该计划完成最终执行。请查看与执行计划相关的基本文档以获取更多详细信息。

于 2013-03-29T10:03:32.453 回答