索引调整问题


8

我正在调整一些索引,看到一些问题想听取您的建议

在1个表上有3个索引

dbo.Address.IX_Address_ProfileId 
[1 KEY] ProfileId {int 4}
Reads: 0 Writes:10,519

dbo.Address.IX_Address 
[2 KEYS] ProfileId {int 4}, InstanceId {int 4}
Reads: 0 Writes:10,523

dbo.Address.IX_Address_profile_instance_addresstype
[3 KEYS] ProfileId {int 4}, InstanceId {int 4}, AddressType {int 4}
Reads: 149677 (53,247 seek) Writes:10,523

1-我真的需要前两个索引,还是应该删除它们?

2-正在运行的查询使用profileid = xxxx的使用条件,以及其他使用profileid = xxxx且InstanceID = xxxxxx的使用条件。为什么优化器选择第三索引而不是第一索引或第二索引?

我也正在运行一个查询,使每个索引上的Lock等待。如果我得到这些计数,应该怎么做才能调整该指数?

Row lock waits: 484; total duration: 59 minutes; avg duration: 7 seconds; 
Page lock waits: 5; total duration: 11 seconds; avg duration: 2 seconds; 
Lock escalation attempts: 36,949; Actual Escalations: 0.

表结构是

TABLE [dbo].[Address](
[Id] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[AddressType] [int] NULL,
[isPreferredAddress] [bit] NULL,
[StreetAddress1] [nvarchar](255) NULL,
[StreetAddress2] [nvarchar](255) NULL,
[City] [nvarchar](50) NULL,
[State_Id] [int] NOT NULL,
[Zip] [varchar](20) NULL,
[Country_Id] [int] NOT NULL,
[CurrentUntil] [date] NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedDate] [datetime] NOT NULL,
[ProfileId] [int] NOT NULL,
[InstanceId] [int] NOT NULL,
[County_id] [int] NULL,
 CONSTRAINT [PK__Address__3214EC075E4BE276] PRIMARY KEY CLUSTERED 
(
   [Id] ASC
 )

这是一个示例(此查询由hibernate创建,因此看起来很奇怪)

(@P0 bigint)select addresses0_.ProfileId as Profile15_109_1_
, addresses0_.Id as Id1_20_1_
, addresses0_.Id as Id1_20_0_
, addresses0_.AddressType as AddressT2_20_0_
, addresses0_.City as City3_20_0_
, addresses0_.Country_Id as Country_4_20_0_
, addresses0_.County_id as County_i5_20_0_
, addresses0_.CreatedDate as CreatedD6_20_0_
, addresses0_.CurrentUntil as CurrentU7_20_0_
, addresses0_.InstanceId as Instance8_20_0_
, addresses0_.isPreferredAddress as isPrefer9_20_0_
, addresses0_.ProfileId as Profile15_20_0_
, addresses0_.State_Id as State_I10_20_0_
, addresses0_.StreetAddress1 as StreetA11_20_0_
, addresses0_.StreetAddress2 as StreetA12_20_0_
, addresses0_.UpdatedDate as Updated13_20_0_
, addresses0_.Zip as Zip14_20_0_ 
from dbo.Address addresses0_ 
where addresses0_.ProfileId=@P0 

在此处输入图片说明

(@P0 bigint,@P1 bigint)
select addressdmo0_.Id as Id1_20_
, addressdmo0_.AddressType as AddressT2_20_
, addressdmo0_.City as City3_20_
, addressdmo0_.Country_Id as Country_4_20_
, addressdmo0_.County_id as County_i5_20_
, addressdmo0_.CreatedDate as CreatedD6_20_
, addressdmo0_.CurrentUntil as CurrentU7_20_
, addressdmo0_.InstanceId as Instance8_20_
, addressdmo0_.isPreferredAddress as isPrefer9_20_
, addressdmo0_.ProfileId as Profile15_20_
, addressdmo0_.State_Id as State_I10_20_
, addressdmo0_.StreetAddress1 as StreetA11_20_
, addressdmo0_.StreetAddress2 as StreetA12_20_
, addressdmo0_.UpdatedDate as Updated13_20_
, addressdmo0_.Zip as Zip14_20_ 
from dbo.Address addressdmo0_ 
left outer join dbo.Profile profiledmo1_ 
on addressdmo0_.ProfileId=profiledmo1_.Id 
where profiledmo1_.Id=@P0 and addressdmo0_.InstanceId=@P1

在此处输入图片说明


您可能会添加所有的完整表结构,集群键是什么,然后在正在寻找profileid = xxxx的查询以及profilerid = xxxx和instanceid = xxxx的查询中包括哪些其他列。这些答案中有很多“取决于”,拥有这些信息肯定会有助于解释其取决于什么。
mskinner

有关数据的更多信息将很有帮助。例如,如果表中的统计信息已更新,则表中有多少条记录以及唯一性等等。
Glen Swan

@GlenSwan,此表中有567644条记录。统计每周更新两次。星期二和星期六
sebeid 2015年

2
请您自己进行功能比较研究。尽管有一些重叠,但故障转移群集和可用性组具有不同的功能并满足不同的要求,因此您不能真正地一般性地问哪个更好。您需要将每种功能与实际业务需求进行比较。另外,许可/成本问题不在这里。请完整阅读此meta文章
亚伦·伯特兰

Answers:


6

回答问题1:

从您发布的内容中,您可以删除前两个索引,因为第三个索引将涵盖您提到的所有查询,并且查询优化器在构建查询计划(基于您发布的计划)时也会看到该内容。

对问题2的回答:

它始终使用第三个索引,因为使用另外两个索引键(InstanceId and AddressType)在索引中已有更多数据。这使SQL不必从主键(执行计划的键查找部分)中提取InstanceId和AddressType来满足查询。

我的建议是删除前两个索引,并用包含列重建第三个索引,以覆盖查询中请求的其他列

Create index IX_Address_profile_instance_addresstype 
on dbo.address  (ProfileId, InstanceId, AddressType) 
include(<put in the remaining columns comma delimited>) 
with (drop_existing=on,sort_in_tempdb=on)

这将有助于查询,并应从查询计划中删除键查找。

看看这些更改之后锁是否会脱落,如果没有,我们可以更深入地研究。


我做了你的建议,没有更多的关键查找。我正在监视锁..我仍然需要澄清这些计数行锁等待:484; 总时长:59分钟;平均持续时间:7秒;页面锁定等待:5;总时长:11秒;平均持续时间:2秒;锁定升级尝试次数:36,949;实际上报:0
sebeid

@sebeid在地址表上完成插入/更新/删除操作时,其他表是否也被同一批处理请求修改?如果是这样,该批处理是否显式地开始批量处理所有修改语句的事务,并且仅在该批处理结束时提交或回滚?
亚伦

我不知道,我从哪里可以得到这些信息。谢谢
sebeid

2
@sebeid,如果一切都是从休眠生成的语句,我会问您的开发人员,因为这可能是最简单的方法,否则您将需要跟踪或设置扩展事件来尝试捕获调用,以便可以看到所有发生的情况批处理语句。扩展事件 探查器示例
亚伦

3

不是所陈述的问题,而是通过更好的查询可能会得到更好的查询计划
您正在使用
profiledmo1_.Id=@P0将其变成联接 的位置杀死左外部

在索引上仅前两个

select addressdmo0_.Id as Id1_20_
     , ...
     , addressdmo0_.Zip as Zip14_20_ 
  from dbo.Address addressdmo0_ 
  join dbo.Profile profiledmo1_ 
    on addressdmo0_.ProfileId = profiledmo1_.Id 
   and profiledmo1_.Id = @P0 
   and addressdmo0_.InstanceId = @P1

联接所做的只是确保它位于个人档案中,但您没有报告个人档案中的任何内容,
那是什么呢?

select addressdmo0_.Id as Id1_20_
     , ...
     , addressdmo0_.Zip as Zip14_20_ 
  from dbo.Address addressdmo0_ 
 where addressdmo0_.ProfileId  = @P0 
   and addressdmo0_.InstanceId = @P1

2

似乎您可以删除索引1和2,因为索引3包含了您需要的所有信息(列)。另一个索引作为代表主键的聚簇索引可能有意义。

有了这些有限的信息,我们只能猜测。如果您需要更多提示,请发布更详细的信息,作为完整的表结构(表,索引,键等),查询和执行计划。


1
或不代表主键的聚集索引。尽管这两件事通常彼此紧密关联,并且默认情况下将主键创建为集群时,但它们并非相同(也不必相同)。
亚伦·伯特兰

当然是这样 :-)
乔什·阿尔沃
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.