具有现有索引的大表上的 SELECT 性能突然变差

jre*_*121 4 performance sql-server sql-server-2008-r2 index-tuning

我的公司使用一个软件套件,其中我唯一可以真正修改的是数据库。我们一直有性能问题(主要是我们希望尽快解决的硬件问题),但最近在特定区域特别糟糕 - 当它应该小于 5 时加载需要 20-120 秒。我承担了一些用户,在他们(和我的)机器上进行了跟踪,这似乎是有问题的查询:

SELECT s.create_timestamp, s.create_timestamp, s.create_timestamp_tz, s.row_timestamp, log_msg, pre_mod, post_mod, u.first_name, u.mi, u.last_name, log_id
FROM log_events s (NOLOCK), user_mstr u (NOLOCK)
WHERE s.organization_id = '00001'
    AND source1_id = @account_id --Place holder for a client account unique id
    AND source2_id IS NULL
    AND source3_id IS NULL
    AND source4_id IS NULL
    AND s.created_by = u.user_id
Run Code Online (Sandbox Code Playgroud)

我知道 NOLOCK很糟糕,但我无法控制。

它仅在每个新 source1_id 的第一次滞后 - 之后的每次执行都更快 - 而且随着行数的增加,情况似乎变得更糟。我使用尚未运行的 source1_id 手动运行查询SET STATISTICS IO/TIME ON,它返回了中小行数(490),结果如下:

Table 'user_mstr'. Scan count 0, logical reads 6948, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'log_events'. Scan count 1, logical reads 13939, physical reads 1221, read-ahead reads 34, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
  CPU time = 46 ms,  elapsed time = 18751 ms.

SQL Server Execution Times:
  CPU time = 0 ms,  elapsed time = 0 ms.
Run Code Online (Sandbox Code Playgroud)

log_events 表很大(31,847,167 行),用作整个数据库中重大更改的更改/审核日志。这是表和简化索引的创建语句:

CREATE TABLE log_events (
    log_event_id UNIQUEIDENTIFIER NOT NULL,
    organization_id CHAR(5) NOT NULL,
    site_id CHAR(4) NULL,
    source1_id UNIQUEIDENTIFIER NULL,
    source2_id UNIQUEIDENTIFIER NULL,
    source3_id UNIQUEIDENTIFIER NULL,
    source4_id UNIQUEIDENTIFIER NULL,
    event_source_type CHAR(2) NOT NULL,
    log_id CHAR(4) NOT NULL,
    log_msg VARCHAR(4000) NOT NULL,
    pre_mod VARCHAR(1000) NULL,
    post_mod VARCHAR(1000) NULL,
    create_timestamp DATETIME NOT NULL CONSTRAINT DFlog_events_create_timestamp DEFAULT (GETDATE()),
    created_by INT NOT NULL,
    modify_timestamp DATETIME NOT NULL CONSTRAINT DFlog_events_modify_timestamp DEFAULT (GETDATE()),
    modified_by INT NOT NULL,
    row_timestamp TIMESTAMP,
    group_id INT NULL,
    create_timestamp_tz SMALLINT NULL,
    modify_timestamp_tz SMALLINT NULL,
    CONSTRAINT pk_log_events PRIMARY KEY NONCLUSTERED (log_event_id) WITH (FILLFACTOR = 90) ON MAINSYSTEM_INDEX_1
) 
--Simplified Indices:
INDEX inx_log_events1 ON log_events (source1_id, source2_id, source3_id, source4_id)
INDEX inx_log_events3 ON log_events (source1_id, source2_id, event_source_type)
INDEX inx_log_events4 ON log_events (site_id, source2_id, source1_id)
INDEX inx_log_events5 ON log_events (source1_id, event_source_type, site_id, log_event_id)
CLUSTERED INDEX inx_log_events7 ON log_events (create_timestamp, event_source_type)
INDEX inx_log_events8 ON log_events (site_id, source2_id, event_source_type, log_id)
INDEX inx_log_events9 ON log_events (organization_id, site_id, source1_id, source2_id, source3_id, source4_id, event_source_type)
Run Code Online (Sandbox Code Playgroud)

user_mstr 表不是很大,user_id 字段是一个 PK。

在索引方面我是新手,所以我的问题是:

  1. 我可以通过在 organization_id、source1_id、source2_id、source3_id 和 source4_id 字段上创建新索引来提高性能吗?
  2. 如果是,是什么类型?如果没有,我可以在不更改查询的情况下做什么?
  3. 这大约会消耗多少磁盘空间?或者创建这个看似缩减的查询还有什么其他缺点?
  4. 什么可以解释这种性能的突然下降?我们的软件供应商可能在周末进行了一些更改,但我想不出他们会做些什么来产生这种影响。

Rob*_*ley 6

与实际时间相比,CPU 时间很小。

第二次运行查询时,速度很快——大概是一旦数据在 RAM 中(这是从第二次运行中受益的少数事情之一)。

在我看来,问题不是 SQL,而是磁盘。请注意 PAGEIOLATCH 在您的查询运行时等待增加。看看这方面发生了什么。与您的 SAN 人员交谈。查明是否有其他磁盘活动正在进行。查看是否正在重建 RAID 5 或 6 磁盘。

  • “问题......磁盘”这是看待它的一种方式(+1)。或者,添加索引以避免对 log_events 进行扫描。 (2认同)
  • 在一个有 3100 万行的表上,对 log_events 进行了总共 14k 次读取。对我来说,这听起来不像是表扫描。总共 21k 次读取,CPU 时间不到总时间的 1% - 听起来像是坏磁盘。 (2认同)