在SELECT声明中:
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太长,它减慢搜索过程?
addr_a
addr_b
是否有关于这些东西的任何材料值得推荐?
编辑 :我没有指定RDBMS,因为我想知道尽可能多的SQL实现。
再次编辑 :在这里,我得到了有关MySQL和SQL Server的答案,我接受了“ SQL Server”,因为它是详细的答案。欢迎获得有关其他RDBMS的更多答案。
由于您尚未指定要查询的RDBMS,因此,我将编写它在SQL Server上的工作方式,以期简化一点并避免很多技术性。在不同的系统上可能相同或非常相似,但也可能完全不同。
SQL Server将如何处理您的查询
`SELECT name FROM users WHERE address IN (addr_a, addr_b, addr_c, ...);`
几乎完全取决于您在表上具有哪种索引。这是3种基本方案:
方案1 (良好指数)
如果您具有所谓的Covering Index(覆盖索引),这意味着列address上address包含PK索引或聚集索引,或者包含include上的非聚集索引name,则SQL Server会执行称为的操作Index Seek。这意味着它将遍历索引的树结构,并快速查明所需的确切行(或发现它不存在)。由于name列也包含在索引中,因此它将读取它并从那里直接返回。
address
name
Index Seek
方案2 (索引不太好)
当您在address不包含column的column上具有索引时,就是这种情况name。您可能会经常在仅一列中找到这类索引,但是很快就会发现它们在大多数情况下是毫无用处的。您在这里希望SQL Server遍历索引结构(查找)并快速找到包含您的地址的行。但是由于列name现在不存在,所以只能获取该行实际所在的rowID(或PK),因此它将对返回的每一行进行其他索引或表的额外读取,以查找您的行并检索名称。由于读取所需的时间是方案1的3倍,因此SQL Server通常不会决定仅遍历表的所有行而不是使用索引会更便宜。场景3中对此进行了解释。
方案3 (无可用索引)
如果您根本没有索引,或者列地址上没有索引,则会发生这种情况。简单来说,SQL Server遍历所有行,并检查每一行是否符合您的条件。这被称为Index Scan(或者Table Scan如果根本没有索引)。通常情况最糟,最慢。
Index Scan
Table Scan
希望这有助于澄清一些事情。
至于其他有关长字符串变慢的子问题,这种情况的答案“可能不多”。当SQl Server比较两个字符串时,它会逐个字符,因此,如果两个字符串的首字母不同,它将不再进行检查。但是,如果在字符串的开头放置通配符%,即:WHERE address LIKE '%addr_a'SQL Server将必须检查列中每个字符串的每个字符,因此工作起来会慢得多。
WHERE address LIKE '%addr_a'