高 PAGEIOLATCH_SH 在服务器上等待

Rac*_*SQL 1 performance sql-server-2008 sql-server query-performance

编辑:

我知道这个问题已经结束,但我希望它会对某人有所帮助。

问题出在我们的磁盘( cluster )上。

使用 PerfMon,我可以创建一些计数器(磁盘读取和写入)并且读取计数器固定为 100%。

高读取我看到以下等待sp_WhoIsActive



PAGEIOLATCH_SH:Database_Name:1(*)
Run Code Online (Sandbox Code Playgroud)

我在这里看到一些帖子,说这个警告是因为高 I/O。SQL Server 联机丛书将 SQL 等待类型 PAGEIOLATCH_SH 定义为:

当任务正在等待 I/O 请求中的缓冲区的闩锁时发生。锁存请求处于共享模式。

和这个:

用户进程将请求一些当前不在缓冲区缓存中的数据。此时——SQL Server 将尝试分配一个缓冲区页——当数据从磁盘移动到缓冲区缓存时,在缓冲区上创建了一个独占的 PAGEIOLATCH_EX。同时从用户进程的角度在缓冲区上创建一个 PAGEIOLATCH_SH。

我创建了索引和统计信息,还使用了 SQL Server Profiler 来帮助我。

有什么办法可以改进查询吗?我怎样才能改进大量的处理ANDs

我们已经遇到这个问题大约一个星期了,我不知道该怎么办。

SELECT TOP 30 codCliente 
FROM (
    SELECT t1.CodCliente
        , codcampo
        , valor
        , t1.chavealeat 
    FROM tblCliente AS t1 WITH(NOLOCK) 
        INNER JOIN tblClienteDetalhe AS t2 WITH (NOLOCK) 
            ON t1.codcliente = t2.codcliente 
            AND CodCampo IN (-1, 4)
    WHERE codStatus IN(0)  
        AND t1.ChavePeriodo < getdate()
        AND t1.CodStatusLigacao = 0
        AND EXISTS (
            SELECT codcliente 
            FROM tblclientedetalhe WITH (NOLOCK) 
            WHERE codcampo = 3
                AND valor = '2' 
                AND codcliente = t1.codcliente
            )
        AND EXISTS (
            SELECT codcliente 
            FROM tblclientedetalhe WITH (NOLOCK) 
            WHERE codcampo = 6
                AND Convert(DateTime,Valor) BETWEEN '2015-03-01' AND '2015-03-31'
                AND DateDiff(day,Valor,GetDate()) > 15
                AND codcliente = t1.codcliente
            )
        AND NOT EXISTS (
            SELECT 0 
            FROM tblPesquisa WITH (NOLOCK)
            WHERE tblPesquisa.CodCliente = t1.CodCliente
            )
        AND EXISTS (
            SELECT codcliente 
            FROM tblclientedetalhe WITH (NOLOCK) 
            WHERE codcampo = 4
                AND valor = '161' 
                AND codcliente = t1.codcliente
            )
    ) AS Cliente 
PIVOT (
    MAX(Valor) 
    FOR codCampo in ([4])
    ) AS PivotTable
WHERE ([4] = '161')
ORDER BY chavealeat;
Run Code Online (Sandbox Code Playgroud)

编辑1:

正如我在评论中所说的那样,此等待状态还有其他查询。我正在等待一项工作完成以确保这不是问题。

警告

Han*_*non 10

这可能不会直接回答您的问题,但是您的查询中有多个潜在问题,我可以立即看到。

AND Convert(DateTime,Valor) BETWEEN '2015-03-01' AND '2015-03-31'
AND DateDiff(day,Valor,GetDate()) > 15
Run Code Online (Sandbox Code Playgroud)
  1. 你为什么要这样做CONVERT(DateTime, Valor)?是Valor不是DateTime表中的一个类型?如果没有,那你就做错了。

  2. 在列 ( DateDiff(day, Valor, GetDate()))上运行函数并将其与值进行比较使其不可 SARGable。试试这个,而不是:

    AND Valor > DATEADD(DAY, -15, GETDATE())

  3. BETWEEN (x and y)可能不会像您认为的那样运作。您最好使用以下构造,因为它明确定义了您想要的精确日期范围。

    WHERE Valor >= '2015-03-01T00:00:00' AND Valor < '2015-04-01T00:00:00'

  4. WITH (NOLOCK)不是一个更快的按钮!见http://blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere/http://sqlperformance.com/2015/04/t-sql-queries/the-read-uncommitted-isolation-level为关于为什么在大多数情况下无法启动的绝佳细节。