2008-08-28 58 views
21

工作,如果我有这样的查询:做索引与“IN”的条款

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

,我在EmployeeTypeId场有一个指标,不SQL服务器仍然使用该索引?

+2

我不明白为什么这不是一个真正的问题。 – nawfal 2012-07-16 19:19:43

回答

13

是的,没错。如果您的员工表有10,000条记录,并且只有5条记录在(1,2,3)中有employeetypeID,那么它很可能会使用索引来获取记录。但是,如果它发现9,000条记录在(1,2,3)中具有employeeIDType,那么它很可能只是进行表扫描以获得相应的EmployeeID,因为它只是运行整个表的速度比转到索引树的每个分支并单独查看记录。

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

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

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

4

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

2

因此,“IN”子句可能会运行表扫描,但优化程序将尝试并找出处理它的最佳方法?

是否使用索引不会因查询类型而异,因为表中数据的类型和分布多少,表格数据的最新情况以及列的实际数据类型。

其他海报是正确的,指数将在一个表中使用扫描,如果:

  • 查询将不超过行的一定比例索引访问更多(比如说〜10%,但应因人而异在DBMS之间)。
  • 或者,如果列中有很多行,但相对较少的唯一值,那么执行表扫描也可能会更快。

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

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

3

除非技术以我无法想象的方式得到改进,否则显示的“IN”查询将产生一个结果,它有效地对三个结果集进行OR运算,其中一个用于“IN”名单。 IN子句成为每个列表的相等条件,并在适当的情况下使用索引。在唯一ID和足够大的表格的情况下,我希望优化器使用索引。

如果在列表中的项目要成为非唯一然而,我想在一个“TYPEID”是一个外键的例子,那么我更感兴趣的分布。我想知道优化器是否会检查列表中每个值的统计信息?假设它检查第一个值,并发现它在20%的行中(足够大的表格很重要)。它可能会进行表扫描。但是同样的查询计划是否会用于其他两个,即使它们是唯一的?

它可能实际意义 - 有点像一个Employee表可能是足够小,它会在内存中缓存保持和你可能不会注意到,和索引检索之间的差异呢。

最后,当我说教时,要小心IN子句中的查询:它通常是一种快速的方式来获得某些工作,并且(至少对我而言)可以是表达需求的一种好方法,但它几乎总是最好重新加入。你的优化器可能足够聪明来发现这一点,但它可能不会。如果您目前没有性能检查对生产数据卷,这样做 - 在基于成本的优化,这些日子里,你不能确定查询计划,直到你有一个满负荷和有代表性的统计数据。如果不能,那么可以在生产准备的惊喜...

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) 

所以当你和其他人指出,它看起来像有将会是索引被使用或表扫描发生的时间,但是直到运行时才能真正确定。

0
Select EmployeeId From Employee USE(INDEX(EmployeeTypeId)) 

这个查询将搜索使用您所创建的索引。这个对我有用。请做一个尝试..