有没有办法确定 SQL Server 查询是在内存中运行还是在磁盘中运行?

tbo*_*one 13 sql-server-2008 sql-server

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

很明显,在编写这些程序时没有考虑性能,有多个实例只是“不是一个好主意”。

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

然而,程序中涉及的表格大部分都非常小。我在想,如果所有这些表都完全驻留在内存中,那么通过重写其中的任何一个,也许不会获得那么多。

我试图确定......对于这个明显效率低下的代码,它有多大的实际影响?值得修复吗?

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

注意:这是在 SQL Server 2008 R2 上

Seb*_*ine 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;
Run Code Online (Sandbox Code Playgroud)
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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

因此,如果没有运行该查询的索引需要 1,000,000 次读取,而使用 indes 则需要 5 次读取。尽管逻辑读取是内存中的操作,但仍然有很大的成本 - 事实上,它是像上面那样的简单查询中最昂贵的操作。因此,将所需的逻辑读取量减少 200,000 倍将使您的查询速度提高一个相似的倍数。

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

  • 小吹毛求疵 - 我认为页面是 8kb :-)。好答案。 (2认同)