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)
窗口函数正是您所需要的。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)
另一种选择是使用条件条件COUNT或SUM, 对前一行和后行进行窗口化。您仍然需要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)
使用您的样本数据:
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)
你想看:
我们可以使用最多覆盖三行的偏移排序窗口框架来完成所有这些操作:前一行、当前行和下一行。
第一行和最后一行的框架中只有两行。第一行缺少前一行,最后一行缺少后一行。无论活动值如何,我们始终对这些行感兴趣。其他有趣的行在其框架的行之一中将具有 active = 1。
注意:如果只有一个 VLF,则该帧将只有一行,但该行必须处于活动状态。活动行将始终是“有趣的”。
另一种表达方式是说我们对两者都感兴趣:
我们可以将其封装为以下逻辑:
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 调用,以在您的服务器上进行尝试。
| 归档时间: |
|
| 查看次数: |
323 次 |
| 最近记录: |