这不是关于:
这不是关于接受用户输入或使用变量的全面查询的问题。
这完全是关于ISNULL()在WHERE子句中使用where用NULL金丝雀值替换值以与谓词进行比较的查询,以及在 SQL Server中将这些查询重写为SARGable 的不同方法。
你为什么不在那边坐?
我们的示例查询针对 SQL Server 2016 上 Stack Overflow 数据库的本地副本,并查找NULL年龄或年龄 < 18 岁的用户。
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE ISNULL(u.Age, 17) < 18;
Run Code Online (Sandbox Code Playgroud)
查询计划显示了一个非常周到的非聚集索引的扫描。
scan 操作符显示(由于 SQL Server 的最新版本中对实际执行计划 XML 的补充)我们读取了每一行。
总的来说,我们进行了 9157 次读取并使用了大约半秒的 CPU 时间:
Table 'Users'. Scan count 1, logical reads 9157, 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 = 485 ms, elapsed time = 483 ms.
Run Code Online (Sandbox Code Playgroud)
问题是:有 什么方法可以重写此查询以使其更高效,甚至可能是 SARGable?
随意提供其他建议。我认为我的答案不一定就是答案,而且有足够多的聪明人提出可能更好的替代方案。
如果您想在自己的计算机上玩,请前往此处下载 SO 数据库。
谢谢!
Eri*_*ing 61
答案部分
有多种方法可以使用不同的 T-SQL 构造来重写它。我们将查看优缺点并在下面进行整体比较。
首先:使用OR
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE u.Age < 18
OR u.Age IS NULL;
Run Code Online (Sandbox Code Playgroud)
UsingOR为我们提供了一个更有效的 Seek 计划,它读取我们需要的确切行数,但是它添加了技术世界a whole mess of malarkey对查询计划的调用。
还要注意,这里执行了两次 Seek,这从图形操作符中应该更明显:
Table 'Users'. Scan count 2, logical reads 8233, 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 = 469 ms, elapsed time = 473 ms.
Run Code Online (Sandbox Code Playgroud)
其次:在UNION ALL
我们的查询中使用派生表也可以像这样重写
SELECT SUM(Records)
FROM
(
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records);
Run Code Online (Sandbox Code Playgroud)
这产生了相同类型的计划,更少的恶意,以及更明显的关于索引被寻求(寻求?)多少次的诚实程度。
它执行与查询相同的读取量 (8233) OR,但减少了大约 100 毫秒的 CPU 时间。
CPU time = 313 ms, elapsed time = 315 ms.
Run Code Online (Sandbox Code Playgroud)
但是,在这里您必须非常小心,因为如果此计划尝试并行执行,则两个单独的COUNT操作将被序列化,因为它们每个都被视为全局标量聚合。如果我们使用 Trace Flag 8649 强制执行并行计划,问题就很明显了。
SELECT SUM(Records)
FROM
(
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records)
OPTION(QUERYTRACEON 8649);
Run Code Online (Sandbox Code Playgroud)
这可以通过稍微更改我们的查询来避免。
SELECT SUM(Records)
FROM
(
SELECT 1
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT 1
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records)
OPTION(QUERYTRACEON 8649);
Run Code Online (Sandbox Code Playgroud)
现在,执行 Seek 的两个节点都完全并行化,直到我们遇到串联运算符。
就其价值而言,完全并行版本有一些好处。以大约 100 次以上的读取和大约 90 毫秒的额外 CPU 时间为代价,经过的时间缩短到 93 毫秒。
Table 'Users'. Scan count 12, logical reads 8317, 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 = 500 ms, elapsed time = 93 ms.
Run Code Online (Sandbox Code Playgroud)
交叉申请呢?
没有魔法的答案是不完整的CROSS APPLY!
不幸的是,我们遇到了更多的问题COUNT。
SELECT SUM(Records)
FROM dbo.Users AS u
CROSS APPLY
(
SELECT COUNT(Id)
FROM dbo.Users AS u2
WHERE u2.Id = u.Id
AND u2.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u2
WHERE u2.Id = u.Id
AND u2.Age IS NULL
) x (Records);
Run Code Online (Sandbox Code Playgroud)
这个计划太可怕了。当你最后一次出现在圣帕特里克节时,这就是你最终得到的那种计划。虽然很好地并行,但出于某种原因,它正在扫描 PK/CX。呃。该计划的成本为 2198 美元。
Table 'Users'. Scan count 7, logical reads 31676233, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
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.
SQL Server Execution Times:
CPU time = 29532 ms, elapsed time = 5828 ms.
Run Code Online (Sandbox Code Playgroud)
这是一个奇怪的选择,因为如果我们强制它使用非聚集索引,成本会显着下降到 1798 查询美元。
SELECT SUM(Records)
FROM dbo.Users AS u
CROSS APPLY
(
SELECT COUNT(Id)
FROM dbo.Users AS u2 WITH (INDEX(ix_Id_Age))
WHERE u2.Id = u.Id
AND u2.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u2 WITH (INDEX(ix_Id_Age))
WHERE u2.Id = u.Id
AND u2.Age IS NULL
) x (Records);
Run Code Online (Sandbox Code Playgroud)
嘿,寻求!去那边看看 还要注意,使用 的魔法CROSS APPLY,我们不需要做任何愚蠢的事情来拥有一个几乎完全并行的计划。
Table 'Users'. Scan count 5277838, logical reads 31685303, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
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.
SQL Server Execution Times:
CPU time = 27625 ms, elapsed time = 4909 ms.
Run Code Online (Sandbox Code Playgroud)
如果没有这些COUNT东西,Cross apply 最终会表现得更好。
SELECT SUM(Records)
FROM dbo.Users AS u
CROSS APPLY
(
SELECT 1
FROM dbo.Users AS u2
WHERE u2.Id = u.Id
AND u2.Age < 18
UNION ALL
SELECT 1
FROM dbo.Users AS u2
WHERE u2.Id = u.Id
AND u2.Age IS NULL
) x (Records);
Run Code Online (Sandbox Code Playgroud)
该计划看起来不错,但读取和 CPU 并没有改善。
Table 'Users'. Scan count 20, logical reads 17564, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. 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 '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.
SQL Server Execution Times:
CPU time = 4844 ms, elapsed time = 863 ms.
Run Code Online (Sandbox Code Playgroud)
将交叉应用重写为派生连接会导致完全相同的所有内容。我不会重新发布查询计划和统计信息——它们确实没有改变。
SELECT COUNT(u.Id)
FROM dbo.Users AS u
JOIN
(
SELECT u.Id
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT u.Id
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x ON x.Id = u.Id;
Run Code Online (Sandbox Code Playgroud)
关系代数:为了彻底,并防止 Joe Celko 困扰我的梦想,我们至少需要尝试一些奇怪的关系的东西。这里什么都没有!
尝试与 INTERSECT
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE NOT EXISTS ( SELECT u.Age WHERE u.Age >= 18
INTERSECT
SELECT u.Age WHERE u.Age IS NOT NULL );
Run Code Online (Sandbox Code Playgroud)
Table 'Users'. Scan count 1, logical reads 9157, 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 = 1094 ms, elapsed time = 1090 ms.
Run Code Online (Sandbox Code Playgroud)
这是一个尝试 EXCEPT
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE NOT EXISTS ( SELECT u.Age WHERE u.Age >= 18
EXCEPT
SELECT u.Age WHERE u.Age IS NULL);
Run Code Online (Sandbox Code Playgroud)
Table 'Users'. Scan count 7, logical reads 9247, 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 = 2126 ms, elapsed time = 376 ms.
Run Code Online (Sandbox Code Playgroud)
可能有其他的方式来写这些,但我会离开,人谁也许使用EXCEPT和INTERSECT更多的时候比我好。
如果您真的只需要
我COUNT在查询中使用的计数作为速记(阅读:有时我懒得想出更多涉及的场景)。如果你只需要一个计数,你可以使用一个CASE表达式来做同样的事情。
SELECT SUM(CASE WHEN u.Age < 18 THEN 1
WHEN u.Age IS NULL THEN 1
ELSE 0 END)
FROM dbo.Users AS u
SELECT SUM(CASE WHEN u.Age < 18 OR u.Age IS NULL THEN 1
ELSE 0 END)
FROM dbo.Users AS u
Run Code Online (Sandbox Code Playgroud)
它们都获得相同的计划并具有相同的 CPU 和读取特性。
Table 'Users'. Scan count 1, logical reads 9157, 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 = 719 ms, elapsed time = 719 ms.
Run Code Online (Sandbox Code Playgroud)
赢家? 在我的测试中,在派生表上使用 SUM 的强制并行计划执行得最好。是的,可以通过添加几个过滤索引来说明这两个谓词来辅助这些查询中的许多查询,但我想将一些实验留给其他人。
SELECT SUM(Records)
FROM
(
SELECT 1
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT 1
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records)
OPTION(QUERYTRACEON 8649);
Run Code Online (Sandbox Code Playgroud)
谢谢!
Joe*_*ish 19
我不想为一张表恢复 110 GB 的数据库,所以我创建了自己的数据。年龄分布应该与 Stack Overflow 上的匹配,但显然表本身不匹配。我不认为这是一个太大的问题,因为无论如何查询都会命中索引。我正在使用 SQL Server 2016 SP1 的 4 CPU 计算机上进行测试。需要注意的一件事是,对于快速完成的查询,重要的是不要包含实际的执行计划。这可能会减慢速度。
我首先浏览了 Erik 出色答案中的一些解决方案。对于这个:
SELECT SUM(Records)
FROM
(
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records);
Run Code Online (Sandbox Code Playgroud)
我从sys.dm_exec_sessions得到了以下10 次试验的结果(查询对我来说自然是并行的):
?????????????????????????????????????????????????
? cpu_time ? total_elapsed_time ? logical_reads ?
?????????????????????????????????????????????????
? 3532 ? 975 ? 60830 ?
?????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
对 Erik 效果更好的查询实际上在我的机器上表现更差:
SELECT SUM(Records)
FROM
(
SELECT 1
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT 1
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records)
OPTION(QUERYTRACEON 8649);
Run Code Online (Sandbox Code Playgroud)
10 次试验的结果:
?????????????????????????????????????????????????
? cpu_time ? total_elapsed_time ? logical_reads ?
?????????????????????????????????????????????????
? 5704 ? 1636 ? 60850 ?
?????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
我不能立即解释为什么它那么糟糕,但不清楚为什么我们要强制查询计划中的几乎每个运算符并行运行。在原始计划中,我们有一个串行区域,用于查找带有AGE < 18. 只有几千行。在我的机器上,我对查询的那部分进行了 9 次逻辑读取,并获得了 9 毫秒的报告 CPU 时间和已用时间。还有一个用于行的全局聚合的串行区域,AGE IS NULL但每个 DOP 仅处理一行。在我的机器上,这只有四行。
我的结论是优化查找带有NULLfor 的行的查询部分是最重要的,Age因为这些行有数百万。与列上的简单页面压缩页面相比,我无法创建包含数据的页面更少的索引。我假设每行有一个最小索引大小,或者我尝试过的技巧无法避免很多索引空间。因此,如果我们坚持使用大致相同数量的逻辑读取来获取数据,那么加快速度的唯一方法是使查询更加并行,但这需要以不同于 Erik 使用 TF 的查询的方式完成8649. 在上面的查询中,CPU 时间与经过时间的比率为 3.62,这是相当不错的。理想的情况是我的机器上的比率为 4.0。
一个可能的改进领域是在线程之间更平均地分配工作。在下面的屏幕截图中,我们可以看到我的一个 CPU 决定休息一下:
索引扫描是少数可以并行实现的运算符之一,我们无法对行如何分配给线程做任何事情。它也有机会的元素,但我一直看到一个工作不足的线程。解决此问题的一种方法是以困难的方式进行并行:在嵌套循环连接的内部。嵌套循环内部的任何内容都将以串行方式实现,但许多串行线程可以并发运行。只要我们得到一个有利的并行分配方式(比如轮询),我们就可以准确控制向每个线程发送多少行。
我正在使用 DOP 4 运行查询,因此我需要将NULL表中的行平均分为四个存储桶。一种方法是在计算列上创建一堆索引:
ALTER TABLE dbo.Users
ADD Compute_bucket_0 AS (CASE WHEN Age IS NULL AND Id % 4 = 0 THEN 1 ELSE NULL END),
Compute_bucket_1 AS (CASE WHEN Age IS NULL AND Id % 4 = 1 THEN 1 ELSE NULL END),
Compute_bucket_2 AS (CASE WHEN Age IS NULL AND Id % 4 = 2 THEN 1 ELSE NULL END),
Compute_bucket_3 AS (CASE WHEN Age IS NULL AND Id % 4 = 3 THEN 1 ELSE NULL END);
CREATE INDEX IX_Compute_bucket_0 ON dbo.Users (Compute_bucket_0) WITH (DATA_COMPRESSION = PAGE);
CREATE INDEX IX_Compute_bucket_1 ON dbo.Users (Compute_bucket_1) WITH (DATA_COMPRESSION = PAGE);
CREATE INDEX IX_Compute_bucket_2 ON dbo.Users (Compute_bucket_2) WITH (DATA_COMPRESSION = PAGE);
CREATE INDEX IX_Compute_bucket_3 ON dbo.Users (Compute_bucket_3) WITH (DATA_COMPRESSION = PAGE);
Run Code Online (Sandbox Code Playgroud)
我不太确定为什么四个单独的索引比一个索引快一点,但这是我在测试中发现的一个。
要获得并行嵌套循环计划,我将使用未记录的跟踪标志 8649。我还将编写一些有点奇怪的代码,以鼓励优化器不要处理多余的行。下面是一种似乎运行良好的实现:
SELECT SUM(t.cnt) + (SELECT COUNT(*) FROM dbo.Users AS u WHERE u.Age < 18)
FROM
(VALUES (0), (1), (2), (3)) v(x)
CROSS APPLY
(
SELECT COUNT(*) cnt
FROM dbo.Users
WHERE Compute_bucket_0 = CASE WHEN v.x = 0 THEN 1 ELSE NULL END
UNION ALL
SELECT COUNT(*) cnt
FROM dbo.Users
WHERE Compute_bucket_1 = CASE WHEN v.x = 1 THEN 1 ELSE NULL END
UNION ALL
SELECT COUNT(*) cnt
FROM dbo.Users
WHERE Compute_bucket_2 = CASE WHEN v.x = 2 THEN 1 ELSE NULL END
UNION ALL
SELECT COUNT(*) cnt
FROM dbo.Users
WHERE Compute_bucket_3 = CASE WHEN v.x = 3 THEN 1 ELSE NULL END
) t
OPTION (QUERYTRACEON 8649);
Run Code Online (Sandbox Code Playgroud)
十次试验的结果:
?????????????????????????????????????????????????
? cpu_time ? total_elapsed_time ? logical_reads ?
?????????????????????????????????????????????????
? 3093 ? 803 ? 62008 ?
?????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)
通过该查询,我们的 CPU 与运行时间之比为 3.85!我们从运行时缩短了 17 毫秒,并且只需要 4 个计算列和索引就可以做到!每个线程处理的总行数非常接近,因为每个索引的行数都非常接近,并且每个线程只扫描一个索引:
最后,我们还可以点击简单按钮,向Age列中添加一个非集群 CCI :
CREATE NONCLUSTERED COLUMNSTORE INDEX X_NCCI ON dbo.Users (Age);
Run Code Online (Sandbox Code Playgroud)
以下查询在我的机器上在 3 毫秒内完成:
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE u.Age < 18 OR u.Age IS NULL;
Run Code Online (Sandbox Code Playgroud)
这将很难被击败。
虽然我没有 Stack Overflow 数据库的本地副本,但我可以尝试几个查询。我的想法是从系统目录视图中获取用户数(而不是直接从基础表中获取行数)。然后计算符合(或可能不符合)Erik 标准的行数,并做一些简单的数学运算。
我使用Stack Exchange Data Explorer(连同SET STATISTICS TIME ON;和SET STATISTICS IO ON;)来测试查询。作为参考,以下是一些查询和 CPU/IO 统计信息:
查询 1
--Erik's query From initial question.
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE ISNULL(u.Age, 17) < 18;
Run Code Online (Sandbox Code Playgroud)
SQL Server 执行时间:CPU 时间 = 0 毫秒,已用时间 = 0 毫秒。(返回 1 行)
表“用户”。扫描计数17,逻辑读201567,物理读0,预读2740,lob逻辑读0,lob物理读0,lob预读0。
SQL Server 执行时间:CPU 时间 = 1829 毫秒,已用时间 = 296 毫秒。
查询 2
--Erik's "OR" query.
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE u.Age < 18
OR u.Age IS NULL;
Run Code Online (Sandbox Code Playgroud)
SQL Server 执行时间:CPU 时间 = 0 毫秒,已用时间 = 0 毫秒。(返回 1 行)
表“用户”。扫描计数17,逻辑读201567,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
SQL Server 执行时间:CPU 时间 = 2500 毫秒,已用时间 = 147 毫秒。
查询 3
--Erik's derived tables/UNION ALL query.
SELECT SUM(Records)
FROM
(
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records);
Run Code Online (Sandbox Code Playgroud)
SQL Server 执行时间:CPU 时间 = 0 毫秒,已用时间 = 0 毫秒。(返回 1 行)
表“用户”。扫描计数 34,逻辑读取 403134,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
SQL Server 执行时间:CPU 时间 = 3156 毫秒,已用时间 = 215 毫秒。
第一次尝试
这比我在这里列出的所有 Erik 的查询都要慢……至少在经过的时间方面。
SELECT SUM(p.Rows) -
(
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE u.Age >= 18
)
FROM sys.objects o
JOIN sys.partitions p
ON p.object_id = o.object_id
WHERE p.index_id < 2
AND o.name = 'Users'
AND SCHEMA_NAME(o.schema_id) = 'dbo'
GROUP BY o.schema_id, o.name
Run Code Online (Sandbox Code Playgroud)
SQL Server 执行时间:CPU 时间 = 0 毫秒,已用时间 = 0 毫秒。(返回 1 行)
表“工作台”。扫描计数 0,逻辑读取 0,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。表 'sysrowsets'。扫描计数 2,逻辑读取 10,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。表 'sysschobjs'。扫描计数 1,逻辑读取 4,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。表“用户”。扫描计数1,逻辑读201567,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
SQL Server 执行时间:CPU 时间 = 593 毫秒,已用时间 = 598 毫秒。
第二次尝试
在这里,我选择了一个变量来存储用户总数(而不是子查询)。与第一次尝试相比,扫描计数从 1 增加到 17。逻辑读取保持不变。然而,经过的时间大大减少。
DECLARE @Total INT;
SELECT @Total = SUM(p.Rows)
FROM sys.objects o
JOIN sys.partitions p
ON p.object_id = o.object_id
WHERE p.index_id < 2
AND o.name = 'Users'
AND SCHEMA_NAME(o.schema_id) = 'dbo'
GROUP BY o.schema_id, o.name
SELECT @Total - COUNT(*)
FROM dbo.Users AS u
WHERE u.Age >= 18
Run Code Online (Sandbox Code Playgroud)
SQL Server 执行时间:CPU 时间 = 0 毫秒,已用时间 = 0 毫秒。表“工作台”。扫描计数 0,逻辑读取 0,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。表 'sysrowsets'。扫描计数 2,逻辑读取 10,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。表 'sysschobjs'。扫描计数 1,逻辑读取 4,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
SQL Server 执行时间:CPU 时间 = 0 毫秒,已用时间 = 1 毫秒。(返回 1 行)
表“用户”。扫描计数17,逻辑读201567,物理读0,预读0,lob逻辑读0,lob物理读0,lob预读0。
SQL Server 执行时间:CPU 时间 = 1471 毫秒,已用时间 = 98 毫秒。
其他注意事项: 堆栈交换数据资源管理器不允许 DBCC TRACEON,如下所述:
用户“STACKEXCHANGE\svc_sede”没有运行 DBCC TRACEON 的权限。
| 归档时间: |
|
| 查看次数: |
24316 次 |
| 最近记录: |