有没有一种方法可以确定SQL Server查询是在内存中运行还是在磁盘上运行?


13

今天,我在一个应用程序中遇到了一组存储过程,这些存储过程在长时间运行的过程中被重复调用。在每个过程中,我发现了多个不同的select语句,其中一些在循环内。毫不奇怪,当前使用的这些例程需要几分钟才能运行,而直觉会期望它们在几秒钟内完成。

似乎很明显,编写这些过程时并未考虑性能,因为有很多事例只是“一个不好的主意”。

导入数据时处理每一行需要花费300毫秒,因此处理相对较小的导入需要花费几分钟。

但是,过程中涉及的表大部分很小。我在想,如果所有这些表都完全驻留在内存中,那么重写任何这些表可能并没有获得太多。

我正在尝试确定....对于这个显然效率低下的代码,它有多少实际影响?值得修复吗?

所以问题是:
-有没有办法确定哪些表完全固定在内存中?
-是否有一种方法可以打开跟踪以监视嵌套的存储过程以查找特别昂贵的部分?

注意:这是在SQL Server 2008 R2上

Answers:


12

您可以使用这两个查询之一来查看逻辑读取总数和物理读取总数。

SELECT  DB_NAME(st.dbid) Db,
        OBJECT_NAME(st.objectid, st.dbid) Prc,
        qs.execution_count,
        qs.total_logical_reads,
        qs.total_physical_reads,
        qs.statement_start_offset,
        qs.statement_end_offset,
        st.text
FROM    sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st;

SELECT  DB_NAME(database_id) Db,
        OBJECT_NAME(object_id, database_id) Prc,
        execution_count,
        total_logical_reads,
        total_physical_reads
FROM    sys.dm_exec_procedure_stats ps;

第一个按语句细分,第二个在整个过程中计数。

物理读取是针对磁盘的,逻辑读取是针对内存的。您可以使用它来确定哪些过程或语句是系统中最昂贵的过程或语句,然后尝试进行调整。

请记住,虽然逻辑读取比物理读取便宜得多,但它们仍然昂贵,因此减少逻辑读取的数量(例如,通过添加适当的索引)可以使查询的运行速度大大提高。

上面的DMV中还有很多其他的列,您可能也会觉得很有趣。


索引如何帮助减少逻辑读取?

在SQL Server中,所有数据都以块为单位组织,大小为8KB。这些块称为“页面”。

每个表都包含“元”页面,这些页面包含有关表结构以及pata页面的信息。如果不存在索引,并且您运行的查询类似SELECT * FROM tbl WHERE Id = 7SQL Server,则必须在整个表中查找此行或这些行。因此,它一次读取一页,循环遍历每一页中的所有行,以确定适合该WHERE子句的行。因此,如果该表需要存储1,000,000页,则此查询将执行1,000,000逻辑读取。

如果您有索引,则SQL Server会对页面内的数据进行逻辑排序,并在页面之间建立链接列表。这允许运行带有的运行查询,ORDER BY而无需进行昂贵的排序操作。但是,更重要的是,对于排序,SQL Server将B + Tree添加到表中。B + Tree是一种与书中的索引可比的结构,在其中查找特定的关键字使我可以直接跳到包含该关键字的页面。典型的书只有一个索引级别,而B + Tree可以有多个。试想一本大书,索引本身就是多页长。在这种情况下,添加一个额外的索引层是有意义的,该索引层告诉我们在夹心页面S上找到以开头的索引词。

B + Trees被优化为具有尽可能少的级别,同时提供了可以通过在每个索引级别读取一页来找到索引中任何记录的属性。因此,WHERE Id = 7当您有按排序的索引时,请假设上述查询Id。假设该索引有5个级别。现在,要查找与此查询匹配的所有记录,我必须在每个索引级别读取一页(即5页)。这称为“索引查找”。如果有多条符合要求的记录,我可能必须按照排序的索引一段时间才能检索所有记录。但让我们假设只有一条记录。

因此,在不运行索引的情况下,该查询需要1,000,000次读取,而indes则需要5次读取。即使逻辑读取是内存中操作,也要花费大量成本-实际上,这是像上面这样的琐碎查询中最昂贵的操作。因此,将所需的逻辑读取量减少200,000倍,将使查询速度提高近一倍。

因此,逻辑读取不等同于表扫描,但是表扫描导致的逻辑读取要比索引查找多得多。


>“ ...减少它们的数量(例如,通过添加适当的索引)可以使您的查询运行更快。” 您能否解释一下添加索引将如何减少逻辑读取?逻辑读取与表扫描同义吗?

1
在上面的回答中添加了解释。
塞巴斯蒂安·梅恩

谢谢。即使假设在所有涉及的表上都有正确的索引...我认为固定在内存中的表与从磁盘读取的表之间仍然存在巨大的性能差异(在两种情况下都假定相同的索引)...或其他换句话说,在具有大量RAM的计算机上添加索引将比在具有较少内存的计算机上获得%%的性能提升。.对吗?

1
显然,物理磁盘访问要比内存访问贵几个数量级。因此,采取措施避免它会使您走得很远。查询调整时,您仍然应该首先查看逻辑读取数。使其保持在低水平将反过来又使物理读取保持在低水平。也很有可能不必从高速缓存中逐出页面,从而进一步减少了所需的物理读取。
塞巴斯蒂安·梅因

2
小nitpick-我认为页面为8kb :-)。好答案。
onupdatecascade

3
  • 有没有一种方法可以打开跟踪以监视嵌套的存储过程来查找特别昂贵的部分?

您可以使用SQL事件探查器。启动跟踪时,应选择“ RPC已完成”,“ SP启动”,“ SP StmtStarting”和“ SP StmtCompleted”(请参见下图)。

在此处输入图片说明

这将使您看到在存储过程内部运行的每个查询。它会让您看到嵌套存储过程被调用了多少次。跟踪结束后,应保存它。然后,重新打开它,然后,您将能够进行过滤(使用“列过滤器”按钮)以查找引起问题的查询。(例如:花费超过x次读取或持续超过x秒(持续时间)的查询...)

我向您展示的探查器选项还显示了执行计划,这也有很多帮助。


1

似乎是一个一般的查询优化问题。根据您的描述,我会:

  1. 查看代码以查看它是否进行逐行处理。如果是这样,那么通常可以通过使用集合(同时处理多个行)来实现相同的逻辑,从而将数量级提高。换句话说,如果它的作用类似于“循环遍历每一行”,则将其更改为“处理所有行”。SQL之所以能做到这一点,是因为优化器可以从更多可能的方法中进行选择,并可能使用并行性,从而消除了一次一行产生的大量开销。
  2. 接下来,确保有支持该工作的索引。再次,通常,正确的指标可能有几个数量级的改进,反之则不然。在内存和磁盘访问中都是如此。如果大型数据集上没有适当的索引,则将所有内容存储在RAM中的过程仍然需要花费数小时。
  3. 接下来,在设置好逻辑和索引之后,我将查看受影响的数据页是否适合内存。在这一点上,如果仍然有大量磁盘访问,那么查看物理读取和磁盘活动是有意义的,因为从优化中获得的所有重大收益都是在前两个步骤中完成的。
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.