2016-03-08 22 views
2

场景(试图想出一个1-1映射到我的生产场景):获取所有与维珍航空公司或阿联酋航空从纽约飞往的人员列表。为什么SQL查询在最合适时不会使用SELECT的主键?

tbl_Flyer有几列包含关于在任何时间点飞行的人的所有细节。主键是CountryId, CityId, AirlineId, PersonId

现在,一个简单的SQL查询看起来是这样的:

SELECT flyer.PersonId 
FROM tbl_Flyer passenger 
WHERE passenger.CountryId = @countryId 
     AND passenger.City= @cityId 
     AND passenger.AirlineId IN (SELECT values FROM @allAirlineIds) 

@countryId@cityId@allAirlineIds正确发送到SQL存储过程。我的假设是,这个查询将使用主键,因为查询中使用的所有4列都存在于PK中,但由于某种原因它不会。

它使用一个非聚集索引,它被添加到能够根据年龄,性别等个人详细信息查询乘客。 (看起来像(CountryId,CityId,Age,Sex))

我在查询中添加了ForceSeek提示,但我想了解是否有可能在此处使用的反模式?任何想法为什么SQL会违抗逻辑,不使用PK来寻找?

+2

你应该避免构建如此复杂的主键。使用代理标识列作为主键,并为所需的任何列组合附加唯一约束。我建议始终使用'exists'而不是'in(select ...'。 –

+0

主键有助于我对数据库中的数据进行分区,我没有其他直接的选项来根据国家 – divyanshm

+0

不知道按国家划分是否对飞行数据敏感,但你可能有更好的理解,这是一个真正的_partitioning_还是只是一个“影响物理行顺序”的聚集索引?“Country”反正选择性差。没有那么多的国家,你的索引从国家开始,在@allairlineids上你有一些估计问题 –

回答

0

您的数据库引擎使用一个或另一个索引所做的选择是基于自动启发式自动完成的...谁并不总是最准确的。 (99%的时间,他们是,但有时,人类的大脑找到了更好的方法)。 这种启发式算法是基于通用规则计算的,有时候与数据库内容的实际情况不符(字符串一般都是相同的第一个字母,冒号有很多空白的,...)

“Select In”操作必须针对表格的每一行进行,并且存储并且被大多数数据库引擎视为极其昂贵,因此您的数据库可以使用其他方式使用前缀(非聚簇索引case)

顺便说一句,使用Exist in会被认为更便宜,并且会使您的数据库引擎更易于选择索引。

使用ForceSeek,如果它不够。

,你也可以有同样的问题,如果CountryId,CityId,AirlineId的类型,PERSONID不超过@CountryId,@CityId,@AirlineId,@PersonId相同(类型转换为昂贵的)

相关问题