索引是否与“IN”子句一起使用

时间:2008-08-28 02:00:10

标签: sql indexing

如果我有这样的查询:

Select EmployeeId 
From Employee 
Where EmployeeTypeId IN (1,2,3)

我在EmployeeTypeId字段上有一个索引,SQL服务器是否仍然使用该索引?

6 个答案:

答案 0 :(得分:17)

是的,那是对的。如果您的employee表有10,000条记录,并且只有5条记录在(1,2,3)中有employetyypeID,那么它很可能会使用索引来获取记录。但是,如果它发现9,000条记录的employeeIDType在(1,2,3)中,那么它很可能只是进行表扫描以获得相应的EmployeeID,因为它只是运行整个表而不是去索引树的每个分支并单独查看记录。

SQL Server做了很多事情来尝试优化查询的运行方式。但是,有时它得不到正确的答案。如果您知道SQL Server没有使用索引,通过查看查询分析器中的执行计划,您可以告诉查询引擎使用特定索引,并对您的查询进行以下更改。

Select EmployeeId From Employee WITH (Index(Index_EmployeeTypeId )) Where EmployeeTypeId IN (1,2,3)

假设您在EmployeeTypeId字段上的索引名为Index_EmployeeTypeId。

答案 1 :(得分:4)

通常情况下,除非IN子句覆盖了太多的表,然后它会进行表扫描。在特定情况下找出的最佳方法是在查询分析器中运行它,并查看执行计划。

答案 2 :(得分:3)

除非技术在最近我无法想象的方式得到改进,否则显示的“IN”查询将生成一个结果,该结果实际上是三个结果集的OR-ing,一个用于“IN”列表中的每个值。 IN子句成为每个列表的相等条件,并在适当时使用索引。在唯一ID和足够大的表的情况下,我希望优化器使用索引。

如果列表中的项目不是唯一的,我猜在示例中“TypeId”是外键,那么我对分发更感兴趣。我想知道优化器是否会检查列表中每个值的统计数据?假设它检查第一个值并发现它在20%的行中(足够大的表格)。它可能是表扫描。但同样的查询计划是否会用于其他两个,即使它们是唯一的?

这可能没什么问题 - 像Employee表这样的东西可能足够小,以至于它会保留在内存中,你可能不会注意到它和索引检索之间的差异。

最后,当我在讲道时,请注意IN子句中的查询:通常一种快速的方式来获得一些工作并且(至少对我而言)可以是表达要求的好方法,但它几乎总是更好地重申作为一个联接。你的优化者可能足够聪明,可以发现这一点,但话说可能不会。如果您目前没有针对生产数据量进行性能检查,请执行此操作 - 在基于成本的优化的这些天中,在您拥有完整负载和代表性统计信息之前,您无法确定查询计划。如果你做不到,那么就要为生产中的惊喜做好准备......

答案 3 :(得分:2)

  

因此,“IN”子句可能会运行表扫描,但优化器会   试着找出处理它的最佳方法吗?

是否使用索引并不会因查询类型的不同而有所不同,因为表中数据的类型和分布,表统计信息的最新状态以及实际数据类型专栏。

其他海报是正确的,如果符合以下情况,将在表扫描中使用索引:

  • 查询不会访问超过索引行的某一百分比(例如~10%,但在DBMS之间应该有所不同)。
  • 或者,如果列中有很多行,但是相对较少的唯一值,那么执行表扫描的速度也会更快。

另一个可能不那么明显的变量是确保被比较的值的数据类型是相同的。在PostgreSQL中,如果你在浮点数上过滤但是你的列由int组成,我认为不会使用索引。还有一些运算符不支持索引使用(同样,在PostgreSQL中,ILIKE运算符就是这样)。

如上所述,如果有疑问,请务必检查查询分析器,并且您的DBMS文档是您的朋友。

答案 4 :(得分:1)

@Mike:感谢您的详细分析。肯定有一些你在那里有趣的点。我发布的示例有点微不足道,但问题的基础来自于使用NHibernate。

使用NHibernate,您可以编写如下的子句:

int[] employeeIds = new int[]{1, 5, 23463, 32523};
NHibernateSession.CreateCriteria(typeof(Employee))
.Add(Restrictions.InG("EmployeeId",employeeIds))

NHibernate然后生成一个类似于

的查询
select * from employee where employeeid in (1, 5, 23463, 32523)

正如您和其他人所指出的那样,看起来有时候会使用索引或者会发生表扫描,但是直到运行时才能真正确定它。

答案 5 :(得分:0)

Select EmployeeId From Employee USE(INDEX(EmployeeTypeId))

此查询将使用您创建的索引进行搜索。这个对我有用。请试试..