SQL Server性能调优-扫描与逻辑读取

时间:2019-03-01 17:41:50

标签: sql sql-server

提出我的问题:如果我可以减少扫描次数(访问表的次数),但以增加读取次数(访问磁盘或缓存的次数)为代价,这更重要吗?

我正在尝试调整某些表之间的一组特定的重复连接,并且我发现SQL Server经常使用次优索引来满足请求。请记住,这是在DEV环境中执行的,因此DBA不会在该环境中维护统计信息和索引(不幸的是)。结果,其中一些问题可能只是缺乏维护。

无论如何,要具体。显然,我无法发布执行计划,因为它会透露有关我们业务的详细信息,但我会尽我所能。首先,这是基本查询的变更版本:

select 
    @audit_id as audit_id,
    @audit_rule_id as audit_rule_id,
    'E' as status_code,
    'TableB' as table_name,
    c.hash_key as table_row_id,
    concat('Rule #7 : hash_key is missing - ', c.source_table,': ', c.hash_key, ', TableB: Null') as status_message
from
    TableA a 
    left join TableB b on
        a.group_id = b.group_id and
        a.hash_key = b.hash_key
    inner join TableC c on
        a.foreign_row_id = c.row_id
where
    a.audit_id = @audit_id and
    a.filter_value = @filter_value and
    b.row_id is null;

我在视图中编写了此连接语法的第二个版本,并在强制执行我特别希望使用的索引的同时公开了所有基础列。该版本如下:

select 
    @audit_id as audit_id,
    @audit_rule_id as audit_rule_id,
    'E' as status_code,
    'TableB' as table_name,
    tablec_hash_key as table_row_id,
    concat('Rule #7 : hash_key is missing - ', source_table,': ', tablec_hash_key, ', TableB: Null') as status_message
from
    MyView
where
    audit_id = @audit_id and
    filter_value = @filter_value and
    tableb_row_id is null;

上面的查询和我刚才描述的视图的两个统计信息都应用了相同的过滤器:

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableB'. Scan count 1, logical reads 439328, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableA'. Scan count 1, logical reads 69, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 49516 ms,  elapsed time = 52285 ms.

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableA'. Scan count 1, logical reads 54, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableB'. Scan count 1, logical reads 413162, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 26156 ms,  elapsed time = 29131 ms.

对TableB中找到的值进行了另一次比较,而不仅仅是不存在检查,并且TableC实际上按以下方式使用:

select 
    @audit_id as audit_id,
    @audit_rule_id as audit_rule_id,
    'E' as status_code,
    'TableB' as table_name,
    b.row_id as table_row_id,
    concat('Rule #1 : Last Name Is Incorrect - ', c.source_table,': ', c.last_name, ', TableB: ', b.last_name) as status_message
from
    TableA a
    inner join TableB b on
        a.group_id = b.group_id and
        a.hash_key = b.hash_key
    inner join TableC c on
        a.foreign_row_id = c.row_id
where
    a.audit_id = @audit_id and
    a.filter_value = @filter_value and
    (
        c.last_name is null and b.last_name is not null or
        c.last_name is not null and b.last_name is null or
        c.last_name != b.last_name
    );

select 
    @audit_id as audit_id,
    @audit_rule_id as audit_rule_id,
    'E' as status_code,
    'TableB' as table_name,
    tableb_row_id as table_row_id,
    concat('Rule #1 : Last Name Is Incorrect - ', source_table,': ', tablec_last_name, ', TableB: ', tableb_last_name) as status_message
from
    MyView
where
    audit_id = @audit_id and
    filter_value = @visit_type_id and
    (
        tablec_last_name is null and tableb_last_name is not null or
        tablec_last_name is not null and tableb_last_name is null or
        tablec_last_name != tableb_last_name
    );

统计数据:

Table 'TableC'. Scan count 22, logical reads 49421, physical reads 40, read-ahead reads 45201, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableC'. Segment reads 0, segment skipped 124.
Table 'TableB'. Scan count 0, logical reads 104353, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableA'. Scan count 1, logical reads 69, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 422 ms,  elapsed time = 724 ms.

Table 'TableB'. Scan count 0, logical reads 104353, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableC'. Scan count 1, logical reads 91411, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'TableA'. Scan count 1, logical reads 54, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 344 ms,  elapsed time = 341 ms.

TableA具有audit_id,filter_value,row_id的唯一聚集索引,以及audit_id,filter_value,group_id,hash_key,foreign_row_id的唯一非聚集索引。由于某种原因,优化器会继续采用“聚簇键”而不是“非聚簇索引”,这将更好地促进联接操作。

TableB在Identity列上具有集群主键和一堆非集群索引,并且在group_id和hash_key上具有唯一约束。由于某种原因,它不会使用唯一约束,而是使用一些不相关的索引并执行索引扫描。

TableC是一个群集列存储,在Identity列上具有非群集主键。即使执行基于行的过滤器,优化器仍会选择Columnstore来执行联接。

0 个答案:

没有答案