查询sys.dm_db_log_info()函数,同时减少到最大值

Joh*_* N. 6 sql-server query dmv sql-server-2016

我目前正在查询sys.dm_db_log_info()DMV 以从数据库检索 VLF,以确定何时可以收缩、重组和减少 TLOG 文件中的碎片量(10 MB VLF)。

原因是,如果事务位于 TLOG 文件末尾并导致活动 VLF,则无法收缩 TLOG 文件。类似的情况,如果活动事务驻留在 TLOG 文件的中间,那么您就无法缩小到超过该 VLF。

当前声明

我目前有这个语句来检索MAX(vlf_begin_offset)记录、MIN(vlf_begin_offset)记录和任何具有 active 的记录vlf_active = 1

SELECT ddli.vlf_begin_offset,
       ddli.vlf_sequence_number,
       ddli.vlf_active,
       ddli.vlf_status,
       ddli.vlf_first_lsn
FROM   sys.dm_db_log_info(DB_ID()) AS ddli
WHERE  ddli.vlf_begin_offset = (
           SELECT MIN(ddli2.vlf_begin_offset)
           FROM   sys.dm_db_log_info(DB_ID()) AS ddli2
       )
       OR  ddli.vlf_active = 1
       OR  ddli.vlf_begin_offset = (
               SELECT MAX(ddli3.vlf_begin_offset)
               FROM   sys.dm_db_log_info(DB_ID()) AS ddli3
           )
ORDER BY
       ddli.vlf_begin_offset ASC
Run Code Online (Sandbox Code Playgroud)

当所有记录都返回时,结果集如下所示:

+------------------+---------------------+------------+------------+------------------------+
| vlf_begin_offset | vlf_sequence_number | vlf_active | vlf_status |     vlf_first_lsn      |
+------------------+---------------------+------------+------------+------------------------+
|             8192 |              253978 |          0 |          0 | 00000000:00000000:0000 |
|           262144 |              253979 |          0 |          0 | 00000000:00000000:0000 |
|           516096 |              253980 |          0 |          0 | 00000000:00000000:0000 |
|           770048 |              253977 |          0 |          0 | 00000000:00000000:0000 |
|          1048576 |              253981 |          0 |          0 | 00000000:00000000:0000 |
|         17563648 |              253982 |          0 |          0 | 00000000:00000000:0000 |
|         34078720 |              253983 |          1 |          2 | 0003e01f:00000010:0001 |
|         50593792 |              253970 |          0 |          0 | 00000000:00000000:0000 |
|         67108864 |              253971 |          0 |          0 | 00000000:00000000:0000 |
|         75497472 |              253972 |          0 |          0 | 00000000:00000000:0000 |
|         83886080 |              253973 |          0 |          0 | 00000000:00000000:0000 |
|         92274688 |              253974 |          0 |          0 | 00000000:00000000:0000 |
|        100663296 |              253975 |          0 |          0 | 00000000:00000000:0000 |
|        109051904 |              253976 |          0 |          0 | 00000000:00000000:0000 |
|        117440512 |                   0 |          0 |          0 | 00000000:00000000:0000 |
|        236978176 |                   0 |          0 |          0 | 00000000:00000000:0000 |
|        356515840 |                   0 |          0 |          0 | 00000000:00000000:0000 |
|        476053504 |                   0 |          0 |          0 | 00000000:00000000:0000 |
|        595591168 |                   0 |          0 |          0 | 00000000:00000000:0000 |
|        715128832 |                   0 |          0 |          0 | 00000000:00000000:0000 |
|        834666496 |                   0 |          0 |          0 | 00000000:00000000:0000 |
|        954204160 |                   0 |          0 |          0 | 00000000:00000000:0000 |
+------------------+---------------------+------------+------------+------------------------+
Run Code Online (Sandbox Code Playgroud)

使用我当前的脚本我得到:

+------------------+---------------------+------------+------------+------------------------+
| vlf_begin_offset | vlf_sequence_number | vlf_active | vlf_status |     vlf_first_lsn      |
+------------------+---------------------+------------+------------+------------------------+
|             8192 |              253978 |          0 |          0 | 00000000:00000000:0000 |
|         34078720 |              253983 |          1 |          2 | 0003e01f:00000010:0001 |
|        954204160 |                   0 |          0 |          0 | 00000000:00000000:0000 |
+------------------+---------------------+------------+------------+------------------------+
Run Code Online (Sandbox Code Playgroud)

附加信息

它们vlf_active = 1可以在不同的位置弹出。可以有多个岛屿vlf_active = 1

问题

vlf_active = 1如果在任何活动的 vlf ( ) 之前有一条记录并在其后有一条记录,那就太好了。

  • 我怎样才能实现这个目标?

      +------------------+---------------------+------------+------------+------------------------+
      | vlf_begin_offset | vlf_sequence_number | vlf_active | vlf_status |     vlf_first_lsn      |
      +------------------+---------------------+------------+------------+------------------------+
      |             8192 |              253978 |          0 |          0 | 00000000:00000000:0000 |
      |         17563648 |              253982 |          0 |          0 | 00000000:00000000:0000 |
      |         34078720 |              253983 |          1 |          2 | 0003e01f:00000010:0001 |
      |         50593792 |              253970 |          0 |          0 | 00000000:00000000:0000 |    
      |        954204160 |                   0 |          0 |          0 | 00000000:00000000:0000 |
      +------------------+---------------------+------------+------------+------------------------+
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果有数百条记录,需要什么才能在其间有一个摘要记录?例如这样的东西:

      +------------------+---------------------+------------+------------+------------------------+
      | vlf_begin_offset | vlf_sequence_number | vlf_active | vlf_status |     vlf_first_lsn      |
      +------------------+---------------------+------------+------------+------------------------+
      |             8192 |              253978 |          0 |          0 | 00000000:00000000:0000 |
      |  (4 res clipped) |                     |            |            |                        |
      |         17563648 |              253982 |          0 |          0 | 00000000:00000000:0000 |
      |         34078720 |              253983 |          1 |          2 | 0003e01f:00000010:0001 |
      |         50593792 |              253970 |          0 |          0 | 00000000:00000000:0000 |    
      | (13 res clipped) |                     |            |            | 00000000:00000000:0000 |    
      |        954204160 |                   0 |          0 |          0 |                        |
      +------------------+---------------------+------------+------------+------------------------+
    
    Run Code Online (Sandbox Code Playgroud)

Cha*_*ace 5

窗口函数正是您所需要的。LAG并会告诉前一行和下一行的值是什么,如果没有这样的行(即第一行或最后一行),LEAD则返回。NULL

SELECT
  ddli.vlf_begin_offset,
  ddli.vlf_sequence_number,
  ddli.vlf_active,
  ddli.vlf_status,
  ddli.vlf_first_lsn
FROM  (
    SELECT *,
      prev_active = LAG (vlf_active) OVER (ORDER BY vlf_begin_offset),
      next_active = LEAD(vlf_active) OVER (ORDER BY vlf_begin_offset)
    FROM sys.dm_db_log_info(DB_ID()) ddli
) ddli
WHERE (
      ddli.vlf_active = 1
   OR ddli.prev_active IS NULL
   OR ddli.prev_active = 1
   OR ddli.next_active IS NULL
   OR ddli.next_active = 1
)
ORDER BY
   ddli.vlf_begin_offset;
Run Code Online (Sandbox Code Playgroud)

如果使用anddefault参数可以简化逻辑LEADLAG

SELECT
  ddli.vlf_begin_offset,
  ddli.vlf_sequence_number,
  ddli.vlf_active,
  ddli.vlf_status,
  ddli.vlf_first_lsn
FROM  (
    SELECT *,
      prev_active = LAG (vlf_active, 1, 1) OVER (ORDER BY vlf_begin_offset),
      next_active = LEAD(vlf_active, 1, 1) OVER (ORDER BY vlf_begin_offset)
    FROM sys.dm_db_log_info(DB_ID()) ddli
) ddli
WHERE 1 IN (ddli.vlf_active, ddli.prev_active, ddli.next_active)
ORDER BY
   ddli.vlf_begin_offset;
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用条件条件COUNTSUM, 对前一行和后行进行窗口化。您仍然需要LEAD LAGorROW_NUMBER来识别第一行和最后一行,所以它不会给您带来太多好处。

SELECT
  ddli.vlf_begin_offset,
  ddli.vlf_sequence_number,
  ddli.vlf_active,
  ddli.vlf_status,
  ddli.vlf_first_lsn
FROM  (
    SELECT *,
      rn = ROW_NUMBER() OVER (ORDER BY vlf_begin_offset),
      next_active = LEAD(vlf_active) OVER (ORDER BY vlf_begin_offset),
      any_active = COUNT(NULLIF(vlf_active, 0)) OVER (ORDER BY vlf_begin_offset ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
    FROM sys.dm_db_log_info(DB_ID()) ddli
) ddli
WHERE ddli.rn = 1
   OR ddli.any_active > 0
   OR ddli.next_active IS NULL
ORDER BY
   ddli.vlf_begin_offset;
Run Code Online (Sandbox Code Playgroud)


Pau*_*ite 2

要求

使用您的样本数据:

DECLARE @LogInfo table
(
    vlf_begin_offset bigint NULL UNIQUE CLUSTERED,
    vlf_sequence_number bigint NULL,
    vlf_active bit NOT NULL,
    vlf_status integer NULL,
    vlf_first_lsn nvarchar(24) NULL
);

INSERT @LogInfo
VALUES
    (     8192, 253978, 0, 0, N'00000000:00000000:0000'),
    (   262144, 253979, 0, 0, N'00000000:00000000:0000'),
    (   516096, 253980, 0, 0, N'00000000:00000000:0000'),
    (   770048, 253977, 0, 0, N'00000000:00000000:0000'),
    (  1048576, 253981, 0, 0, N'00000000:00000000:0000'),
    ( 17563648, 253982, 0, 0, N'00000000:00000000:0000'),
    ( 34078720, 253983, 1, 2, N'0003e01f:00000010:0001'),
    ( 50593792, 253970, 0, 0, N'00000000:00000000:0000'),
    ( 67108864, 253971, 0, 0, N'00000000:00000000:0000'),
    ( 75497472, 253972, 0, 0, N'00000000:00000000:0000'),
    ( 83886080, 253973, 0, 0, N'00000000:00000000:0000'),
    ( 92274688, 253974, 0, 0, N'00000000:00000000:0000'),
    (100663296, 253975, 0, 0, N'00000000:00000000:0000'),
    (109051904, 253976, 0, 0, N'00000000:00000000:0000'),
    (117440512,      0, 0, 0, N'00000000:00000000:0000'),
    (236978176,      0, 0, 0, N'00000000:00000000:0000'),
    (356515840,      0, 0, 0, N'00000000:00000000:0000'),
    (476053504,      0, 0, 0, N'00000000:00000000:0000'),
    (595591168,      0, 0, 0, N'00000000:00000000:0000'),
    (715128832,      0, 0, 0, N'00000000:00000000:0000'),
    (834666496,      0, 0, 0, N'00000000:00000000:0000'),
    (954204160,      0, 0, 0, N'00000000:00000000:0000');
Run Code Online (Sandbox Code Playgroud)

你想看:

  • 按偏移顺序排列的第一行
  • 按偏移顺序排列的最后一行
  • 任何活跃 = 1 的行
  • 偏移顺序中的下一行处于活动状态的任何行 = 1
  • 偏移顺序中前一行处于活动状态的任何行 = 1

解决方案

我们可以使用最多覆盖三行的偏移排序窗口框架来完成所有这些操作:前一行、当前行和下一行。

第一行和最后一行的框架中只有两行。第一行缺少前一行,最后一行缺少后一行。无论活动值如何,我们始终对这些行感兴趣。其他有趣的行在其框架的行之一中将具有 active = 1。

注意:如果只有一个 VLF,则该帧将只有一行,但该行必须处于活动状态。活动行将始终是“有趣的”。

另一种表达方式是说我们对两者都感兴趣:

  • 三行框架中只有两行的行
  • 任何帧行中 active = 1 的行

我们可以将其封装为以下逻辑:

SELECT
    Q1.vlf_begin_offset,
    Q1.vlf_sequence_number,
    Q1.vlf_active,
    Q1.vlf_status,
    Q1.vlf_first_lsn
FROM 
(
    SELECT 
        LI.*,
        is_interesting =
            IIF
            (
                -- First & last rows have only two in frame
                2 =
                COUNT_BIG(*) OVER (
                    ORDER BY LI.vlf_begin_offset 
                    ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
                -- Any row in frame is active
                OR 1 =
                MAX(CONVERT(bigint, LI.vlf_active)) OVER (
                    ORDER BY LI.vlf_begin_offset 
                    ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING),
                1,
                0
            )
    FROM @LogInfo AS LI
) AS Q1
WHERE
    Q1.is_interesting = 1
ORDER BY
    Q1.vlf_begin_offset;
Run Code Online (Sandbox Code Playgroud)

执行计划

结果:

vlf_开始_偏移量 vlf_序列号 vlf_活动 vlf_状态 vlf_first_lsn
8192 253978 0 0 00000000:00000000:0000
17563648 253982 0 0 00000000:00000000:0000
34078720 253983 1 2 0003e01f:00000010:0001
50593792 253970 0 0 00000000:00000000:0000
954204160 0 0 0 00000000:00000000:0000

有摘要记录

生成问题中显示的隐藏记录的摘要只是稍微困难一些。我们首先需要一种方法来识别我们想要跳过的连续行组。

这可以通过对偏移排序帧中当前行之前(包括当前行)中感兴趣的行数求和来完成:

SELECT
    Q1.*,
    grp = 
        SUM(Q1.is_interesting) OVER (
            ORDER BY Q1.vlf_begin_offset 
            ROWS UNBOUNDED PRECEDING)
FROM 
(
    SELECT 
        LI.*,
        is_interesting =
            IIF
            (
                2 =
                COUNT_BIG(*) OVER (
                    ORDER BY LI.vlf_begin_offset 
                    ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
                OR 1 =
                MAX(CONVERT(bigint, LI.vlf_active)) OVER (
                    ORDER BY LI.vlf_begin_offset 
                    ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING),
                1,
                0
            )
    FROM @LogInfo AS LI
) AS Q1
ORDER BY
    Q1.vlf_begin_offset;
Run Code Online (Sandbox Code Playgroud)

结果:

vlf_开始_偏移量 vlf_序列号 vlf_活动 vlf_状态 vlf_first_lsn 很有趣
8192 253978 0 0 00000000:00000000:0000 1 1
262144 253979 0 0 00000000:00000000:0000 0 1
516096 253980 0 0 00000000:00000000:0000 0 1
770048 253977 0 0 00000000:00000000:0000 0 1
1048576 253981 0 0 00000000:00000000:0000 0 1
17563648 253982 0 0 00000000:00000000:0000 1 2
34078720 253983 1 2 0003e01f:00000010:0001 1 3
50593792 253970 0 0 00000000:00000000:0000 1 4
67108864 253971 0 0 00000000:00000000:0000 0 4
75497472 253972 0 0 00000000:00000000:0000 0 4
83886080 253973 0 0 00000000:00000000:0000 0 4
92274688 253974 0 0 00000000:00000000:0000 0 4
100663296 253975 0 0 00000000:00000000:0000 0 4
109051904 253976 0 0 00000000:00000000:0000 0 4
117440512 0 0 0 00000000:00000000:0000 0 4
236978176 0 0 0 00000000:00000000:0000 0 4
356515840 0 0 0 00000000:00000000:0000 0 4
476053504 0 0 0 00000000:00000000:0000 0 4
595591168 0 0 0 00000000:00000000:0000 0 4
715128832 0 0 0 00000000:00000000:0000 0 4
834666496 0 0 0 00000000:00000000:0000 0 4
954204160 0 0 0 00000000:00000000:0000 1 5

所需的输出显示不感兴趣的行没有数据,因此将它们替换为空值:

SELECT
    vlf_begin_offset = IIF(Q1.is_interesting = 1, Q1.vlf_begin_offset, NULL),
    vlf_sequence_number = IIF(Q1.is_interesting = 1, Q1.vlf_sequence_number, NULL),
    vlf_active = IIF(Q1.is_interesting = 1, Q1.vlf_active, NULL),
    vlf_status = IIF(Q1.is_interesting = 1, Q1.vlf_status, NULL),
    vlf_first_lsn = IIF(Q1.is_interesting = 1, Q1.vlf_first_lsn, NULL),
    Q1.is_interesting,
    grp = 
        SUM(Q1.is_interesting) OVER (
            ORDER BY Q1.vlf_begin_offset 
            ROWS UNBOUNDED PRECEDING)
FROM 
(
    SELECT 
        LI.*,
        is_interesting =
            IIF
            (
                2 =
                COUNT_BIG(*) OVER (
                    ORDER BY LI.vlf_begin_offset 
                    ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
                OR 1 =
                MAX(CONVERT(bigint, LI.vlf_active)) OVER (
                    ORDER BY LI.vlf_begin_offset 
                    ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING),
                1,
                0
            )
    FROM @LogInfo AS LI
) AS Q1
ORDER BY
    Q1.vlf_begin_offset;
Run Code Online (Sandbox Code Playgroud)

结果:

vlf_开始_偏移量 vlf_序列号 vlf_活动 vlf_状态 vlf_first_lsn 很有趣
8192 253978 0 0 00000000:00000000:0000 1 1
无效的 无效的 无效的 无效的 无效的 0 1
无效的 无效的 无效的 无效的 无效的 0 1
无效的 无效的 无效的 无效的 无效的 0 1
无效的 无效的 无效的 无效的 无效的 0 1
17563648 253982 0 0 00000000:00000000:0000 1 2
34078720 253983 1 2 0003e01f:00000010:0001 1 3
50593792 253970 0 0 00000000:00000000:0000 1 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
无效的 无效的 无效的 无效的 无效的 0 4
954204160 0 0 0 00000000:00000000:0000 1 5

我们需要总结的所有无趣的行现在在其组内都是相同的。我们可以删除重复项并使用普通的 来计算行数GROUP BY

最终查询

最后的润色会生成自定义的偏移列文本,并确保行以正确的顺序显示:

SELECT
    vlf_begin_offset =
        IIF
        (
            Q2.is_interesting = 1,
            CONVERT(sql_variant, Q2.vlf_begin_offset),
            CONCAT('(', COUNT_BIG(*), ' res clipped)')
        ),
    Q2.vlf_sequence_number,
    Q2.vlf_active,
    Q2.vlf_status,
    Q2.vlf_first_lsn
FROM 
(
    SELECT 
        vlf_begin_offset = IIF(Q1.is_interesting = 1, Q1.vlf_begin_offset, NULL),
        vlf_sequence_number = IIF(Q1.is_interesting = 1, Q1.vlf_sequence_number, NULL),
        vlf_active = IIF(Q1.is_interesting = 1, Q1.vlf_active, NULL),
        vlf_status = IIF(Q1.is_interesting = 1, Q1.vlf_status, NULL),
        vlf_first_lsn = IIF(Q1.is_interesting = 1, Q1.vlf_first_lsn, NULL),
        Q1.is_interesting,
        grp = 
            SUM(Q1.is_interesting) OVER (
                ORDER BY Q1.vlf_begin_offset 
                ROWS UNBOUNDED PRECEDING)
    FROM 
    (
        SELECT 
            LI.*,
            is_interesting =
                IIF
                (
                    2 =
                    COUNT_BIG(*) OVER (
                        ORDER BY LI.vlf_begin_offset 
                        ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)
                    OR 1 =
                    MAX(CONVERT(bigint, LI.vlf_active)) OVER (
                        ORDER BY LI.vlf_begin_offset 
                        ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING),
                    1,
                    0
                )
        FROM @LogInfo AS LI
    ) AS Q1
) AS Q2
GROUP BY 
    Q2.vlf_begin_offset,
    Q2.vlf_sequence_number,
    Q2.vlf_active,
    Q2.vlf_status,
    Q2.vlf_first_lsn,
    Q2.is_interesting,
    Q2.grp
ORDER BY
    Q2.grp,
    Q2.is_interesting DESC;
Run Code Online (Sandbox Code Playgroud)

执行计划概要

结果:

vlf_开始_偏移量 vlf_序列号 vlf_活动 vlf_状态 vlf_first_lsn
8192 253978 0 0 00000000:00000000:0000
(4 分辨率已剪辑) 无效的 无效的 无效的 无效的
17563648 253982 0 0 00000000:00000000:0000
34078720 253983 1 2 0003e01f:00000010:0001
50593792 253970 0 0 00000000:00000000:0000
(13 分辨率已剪辑) 无效的 无效的 无效的 无效的
954204160 0 0 0 00000000:00000000:0000

将表变量的单个引用替换为 DMV 调用,以在您的服务器上进行尝试。