【问题标题】:Will adding a NONCLUSTERED INDEX as suggested by DTA improve performance?按照 DTA 的建议添加非聚集索引会提高性能吗?
【发布时间】:2013-02-23 14:06:54
【问题描述】:

我在数据库中定义了以下表

购物桌

  • 店铺编号
  • 店名
  • 所有者
  • 横幅
  • 标题
  • 城市标识
  • ShopImageId
  • 活动

城市表

  • 城市标识
  • 城市名称
  • 国家标识
  • 区域标识

国家/地区表

  • 国家标识
  • 国名
  • 区域标识

地区

  • 区域标识
  • 地区名称

商店图片

  • 身份证
  • 图片
  • 店铺编号

这是我的选择查询

SELECT ShopName, Owner, CityName, CountryName,RegionName
FROM Shop S 
INNER JOIN City CT ON CT.CityId=S.CityId
INNER JOIN Country CO ON CO.CountryId=CT.CountryId
INNER JOIN Region R ON CT.RegionId=R.RegionId
LEFT OUTER JOIN ShopImages SI ON S.ShopImageId=SI.Id

WHERE S.Banner like '%restaurant%' OR S.Description like '%restaurant%'
AND S.CityId=10 AND S.Active=1

截至目前,city table 有大约 3,000,000 条记录,Shop 有 40,000,000 + 条记录。

获取记录需要时间。所有聚簇索引(主键)都已定义。

我正在尝试在 DTA(Database Tuning Advisor)的帮助下进行优化。 它建议我添加以下索引

CREATE NONCLUSTERED INDEX 
  [_dta_index_CITY_9_2098106515__K9_K20_K1_K2] ON [dbo].[CITY] 
(
    [COUNTRYID] ASC,
    [REGIONID] ASC,
    [CITYID] ASC,
    [CITYNAME] ASC
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) 
  ON [PRIMARY]

是否值得添加此索引?我可以接受 DTA 的所有建议吗?它还建议添加一些统计信息。

如何改进我的上述查询?

【问题讨论】:

  • INNER JOIN Region R ON Region.RegionId=R.RegionId?你确定这是正确的吗?
  • @JoachimIsaksson,谢谢。我现在更新了。错字:)
  • 不过,我会假设INNER JOIN Region R ON CT.RegionId=R.RegionId :)
  • @JoachimIsaksson,似乎 CT 代表 CITY,它没有映射 RegionId。只有 Country 已映射。所以他是对的!
  • @Murali 是的,我很惊讶 DTA 建议包含 CITY.REGIONID 的索引,如果它甚至不在查询中。

标签: sql sql-server performance sql-server-2008 indexing


【解决方案1】:

在分析索引时很难说 DTA 错误,因为我不知道数据分布并且确实如此,但是我要添加的第一个索引超出主键是SHOP.CityIDSHOP.Active 上的(可能是复合的)索引。

我不能在没有测试的情况下给你任何绝对的东西,但这就是推理。

由于您基本上是在 SHOP 上进行过滤并且在任何其他表上都没有过滤器,因此查询的繁重工作很可能是过滤 SHOP 中的 50M 行。

如果数据库从任何其他表开始连接,未过滤连接将导致针对 CITY 的 3M 行,而从过滤 SHOP 开始很可能会导致少得多。编译器喜欢“更少”是有充分理由的。

这是SHOP上的过滤器;

WHERE S.Banner like '%restaurant%' OR S.Description like '%restaurant%'
  AND S.CityId=10 AND S.Active=1

由于以% 开头的LIKE 查询基本上根本无法使用索引,因此您需要S.CityId=10 AND S.Active=1 进行尽可能窄且快速的过滤。如果您对它们进行索引,则其他两个条件不需要扫描超过使用索引找到的几行而不是扫描 - 可能 - 50M 行。

我可以看到建议的索引会产生不小的影响的唯一原因是,如果 CITY 表具有大量字段,并且索引将允许数据库从磁盘读取更少的数据以获取田野。不是说是这样,但只有尝试才能确定。

【讨论】:

  • 不错。想知道为什么 DTA 没有建议这个:) 它只是建议我在 [dbo].[Shop]([ACTIVE], [CITYID]) 上创建统计 [_dta_stat_1250103494_8_19]
  • 在 [ACTIVE]、[CITYID] 上添加索引是否会影响在 WHERE 子句中未使用此组合的其他查询中的任何其他问题?
  • 我认为相反的顺序(即,[CityId],[Active])会更可取,如果 Active 甚至是值得的。(只有两个可能的值不一定有用,可能取决于分布)
  • @HåkanLindqvist,定义连接索引时最重要的考虑因素是如何选择列顺序,以便它可以支持尽可能多的 SQL 查询。这是来自use-the-index-luke.com/sql/where-clause/the-equals-operator/…
  • 很高兴看到订单的影响。我喜欢:)
【解决方案2】:

在某些情况下,您可能需要重新考虑在主键列上设置聚集索引。

例如,如果您通常搜索给定城市中的商店(如果示例查询是“典型查询”就是这种情况),则将 Shop 聚集在 CityId 上可能非常有益(这样所有商店都位于一个给定的城市被组合在一起)

【讨论】:

  • 我已经为 ShopId 创建了聚集索引,因为它是主键。我认为 sql server 会自动在 ShopId 上创建聚集索引。
  • 是的,这是我对你写的东西的印象。我的意思是,您可能需要重新考虑这一点。 (如果更符合您的要求,您可以将 ShopId 上的索引设为非集群索引并在 CityId 上创建集群索引。)
  • 我还有其他查询,例如 WHERE ShopId=5 仅获取商店项目,其中不包括城市。我希望聚集在 ShopId 上是有意义的。请分享你的想法:)
  • 我是说我认为这可能没有意义。查找这样的唯一值不会从具有聚集索引的列中受益,而其他查询能够找到具有相同 CityId 的所有商店的方式会受益。
猜你喜欢
  • 2015-02-24
  • 2017-03-06
  • 2023-03-23
  • 2012-04-30
  • 1970-01-01
  • 2012-05-20
  • 1970-01-01
  • 2011-01-26
  • 2022-01-09
相关资源
最近更新 更多