【问题标题】:SQL Server 2008 Performance: No Indexes vs Bad Indexes?SQL Server 2008 性能:无索引与坏索引?
【发布时间】:2009-06-03 14:26:17
【问题描述】:

我在 Microsoft SQL Server 2008 中遇到了一个奇怪的问题。 我有一个包含大约 10 个表的大型数据库(20 GB),我试图说明如何正确创建索引。

这是我的问题:在一些嵌套查询中,我得到了更快的结果没有使用索引!它很接近(一两秒),但在某些情况下,根本不使用索引似乎会使这些查询运行得更快......我正在运行 Checkpoiunt 和 DBCC dropcleanbuffers 以在运行脚本之前重置缓存,所以我我有点迷路了。

这可能是什么原因造成的? 我知道索引构造不佳(认为每个相关字段一个索引)的事实,重点是证明正确构造它们的重要性,但它应该永远比没有索引慢对吧?

编辑:这是有罪的查询之一:

SET STATISTICS TIME ON
SET STATISTICS IO ON

USE DBX;
GO
CHECKPOINT;
GO
DBCC DROPCLEANBUFFERS;
GO
DBCC FREEPROCCACHE;
GO

SELECT * FROM Identifier where CarId in (SELECT CarID from Car where ManufactId = 14) and DataTypeId = 1

标识符表: - IdentifierId int 不为空 - CarId int 不为空 - DataTypeId int 不为空 - 别名 nvarchar(300)

汽车桌: - CarId int 不为空 - ManufactId int 不为空 - (后面有几个字段,都是 nvarchar(100)

每个要点都有一个索引,以及一些同时存储其中两个的索引(例如 CarId 和 DataTypeId)。

最后,标识符表有超过百万的条目,而汽车表有两三百万

【问题讨论】:

  • 感谢大家的回答!不幸的是,SQL Server 决定应该突然恢复数据库,所以恐怕我暂时被锁定了。 PS:我还在“无索引”方法中删除了主键,但在糟糕的索引中重建了它们

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


【解决方案1】:

我的猜测是 SQL Server 错误地决定使用索引,然后强制进行书签查找*。通常发生这种情况(索引使用不正确)是因为表上的统计信息不正确。

如果您刚刚将大量数据加载到一个或多个表中,则尤其会发生这种情况。或者,可能是 SQL Server 搞砸了。这种情况很少发生(一方面我可以数出我在 SQL Server 的 15 年职业生涯中不得不强制使用索引的次数),但优化器并不完美。

* 书签查找是指 SQL Server 在索引上找到它需要的行,但随后必须转到实际数据页以检索不在索引中的其他列。如果您的结果集返回很多行,则成本可能会很高,而聚集索引扫描可以带来更好的性能。

摆脱书签查找的一种方法是使用覆盖索引 - 一个首先具有过滤列的索引,然后还包括您在“覆盖”查询中需要的任何其他列。例如:

SELECT
     my_string1,
     my_string2
FROM
     My_Table
WHERE
     my_date > '2000-01-01'

覆盖索引将是 (my_date, my_string1, my_string2)

【讨论】:

  • 想到了,虽然自创建索引以来没有执行任何插入操作
  • 关于覆盖索引,如果我搜索 my_string1 和 my_string2 覆盖的索引可以提供答案吗?
  • 它有时会使用索引,尽管 my_string1 和 my_string2 不在索引的开头,它必须是索引扫描。想象一下在电话簿中查找姓氏第二个字母为“a”的人。跳转到每个可能包含该名称的部分(“aa”、“ba”等)比扫描整个电话簿要快,但它不如按首字母查找姓名快。
【解决方案2】:

在您拥有 许多 条记录之前,索引实际上并没有任何好处。我说很多是因为我真的不知道那个临界点是什么......这取决于具体的应用和环境。

SQL Server 使用索引确实需要时间。如果该时间超过了收益...这在子查询中尤其如此,其中小的差异会成倍增加。

如果没有索引效果更好,请忽略索引。

【讨论】:

    【解决方案3】:

    尝试DBCC FREEPROCCACHE 也清除执行计划缓存。

    【讨论】:

    • @gbn+1:迄今为止最明智的评论。 1秒的差异可能是初始查询的编译成本:-)我还建议您(SET STATISTICS IO ON)检查逻辑和物理读取的数量以及(SET STATISTICS TIME ON),以准确监控时间。
    【解决方案4】:

    这是一个空洞的猜测。也许如果你有很多索引,SQL Server 会花时间分析和挑选一个,然后拒绝所有的。如果您没有索引,引擎就不必在这个审查过程中浪费时间。

    这个审查过程实际需要多长时间,我不知道。

    【讨论】:

      【解决方案5】:

      对于某些查询,直接从表中读取(聚集索引扫描)比读取索引并从表中获取记录(索引扫描+书签查找)要快。

      考虑一条记录与数据页中的其他记录一起存在。数据页是IO的基本单元。如果直接读取该表,则以 1 次 IO 为代价可以获得 10 条记录。如果直接读取索引,然后从表中取出记录,则必须为每条记录支付 1 IO。

      通常,SQL Server 非常擅长选择访问表的最佳方式(直接与索引)。您的查询中可能有一些东西使优化器蒙蔽了双眼。查询提示可以指示优化器在错误时使用索引。连接提示可以改变访问表的顺序或方法。优化器认为表变量有 0 条记录,因此如果您的表变量很大 - 优化器可能会选择错误的计划。

      还有一点需要注意 - varchar 与 nvarchar。确保所有参数与目标列的类型相同。有一种情况,如果类型不匹配,SQL Server 会将整个索引转换为参数的类型。

      【讨论】:

      • 嗯,我明白了,虽然我既没有使用不同类型的列,也没有使用表变量。感谢您的洞察力
      【解决方案6】:

      通常,SQL Server 在决定使用什么索引以最快的方式检索数据方面做得很好。很多时候它会决定不使用任何索引,因为它可以更快地从小表中检索少量数据而无需离开索引(在某些情况下)。

      听起来在您的情况下,SQL 可能没有采用最优化的路线。拥有大量创建错误的索引可能会导致它选择错误的路径来获取数据。

      我建议在 Management Studio 中查看查询计划,以检查它使用了哪些索引,以及花费的时间。这应该让您知道从哪里开始。

      另一个注意事项是,这些索引可能随着时间的推移变得支离破碎,现在没有发挥出最佳性能,也许值得检查一下,并在需要时重建其中的一些。

      【讨论】:

        【解决方案7】:

        检查执行计划,看看它是否使用了您“知道”不好的索引之一?

        通常,索引会减慢写入数据的速度,并有助于加快读取数据的速度。

        所以是的,我同意你的看法。它应该从不比完全没有索引要慢。

        【讨论】:

          【解决方案8】:

          SQL 服务器实际上为您创建了一些索引(例如在主键上)。

          索引可能会变得支离破碎。

          过多的索引总是会降低性能(有关于为什么不索引数据库中的每个列的常见问题解答)

          还有some situations where indexes will always be slower

          【讨论】:

          • 杀死了主键并且索引是“新建立的”:S
          【解决方案9】:

          运行:

          SET SHOWPLAN_ALL ON
          

          然后在使用和不使用索引的情况下运行查询,这将让您查看正在使用的索引(如果有的话)、“工作”在哪里等。

          【讨论】:

            【解决方案10】:

            在决定使用索引来加速查询之前,没有 Sql Server 会同时分析索引和统计信息。运行非索引版本完全有可能比索引版本更快。

            尝试一些事情

            1. 确保创建和重建索引,并重新组织(碎片整理)。

            2. 确保自动创建统计信息已打开。

            3. 尝试使用 Sql Profiler 捕获优化配置文件,然后使用数据库引擎优化顾问创建索引。

            令人惊讶的是,用于 Sql 管理的 MS Press 考试书很好地解释了索引和统计数据。

            请参阅本书的亚马逊阅读器预览中的第 4 章目录

            Amazon Reader of Sql 2008 MCTS Exam Book

            【讨论】:

              【解决方案11】:

              在我看来,您的 sql 写得非常糟糕,因此没有利用您正在创建的索引。

              您可以添加索引直到脸色发青,但如果您的查询没有优化以使用这些索引,那么您将不会获得任何性能提升。

              给我们你正在使用的查询示例。

              好吧……

              试试这个,看看你是否获得任何性能提升(使用 pk 索引)

              SELECT i.* 
              FROM Identifier i 
                  inner join Car c
                      on i.CarID=c.CarID
              where c.ManufactId = 14 and i.DataTypeId = 1
              

              【讨论】:

              • 会做的,还在等待恢复……呸
              猜你喜欢
              • 2010-12-20
              • 1970-01-01
              • 2010-11-08
              • 2010-12-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-10-06
              相关资源
              最近更新 更多