我有一个查询需要根据标量 UDF 的结果进行过滤。查询必须作为单个语句发送(因此我不能将 UDF 结果分配给局部变量)并且我不能使用 TVF。我知道标量 UDF 引起的性能问题,包括强制整个计划串行运行、过多的内存授予、基数估计问题和缺乏内联。对于这个问题,请假设我需要使用标量 UDF。
UDF 本身调用起来非常昂贵,但理论上查询可以由优化器在逻辑上以这样一种方式实现,即函数只需要计算一次。我为这个问题模拟了一个大大简化的例子。以下查询在我的机器上执行需要 6152 毫秒:
SELECT x1.ID
FROM dbo.X_100_INTEGERS x1
WHERE x1.ID >= dbo.EXPENSIVE_UDF();
Run Code Online (Sandbox Code Playgroud)
查询计划中的过滤器运算符表明该函数为每一行计算一次:
DDL 和数据准备:
CREATE OR ALTER FUNCTION dbo.EXPENSIVE_UDF () RETURNS INT
AS
BEGIN
DECLARE @tbl TABLE (VAL VARCHAR(5));
-- make the function expensive to call
INSERT INTO @tbl
SELECT [VALUE]
FROM STRING_SPLIT(REPLICATE(CAST('Z ' AS VARCHAR(MAX)), 20000), ' ');
RETURN 1;
END;
GO
DROP TABLE IF EXISTS dbo.X_100_INTEGERS;
CREATE TABLE dbo.X_100_INTEGERS (ID INT NOT NULL);
-- insert 100 …Run Code Online (Sandbox Code Playgroud) 我有一个有点复杂的 Oracle 查询,需要大约半小时才能完成。如果我采用查询的慢部分并单独运行它,它会在几秒钟内完成。这是隔离查询的 SQL Monitor 报告的屏幕截图:
以下是作为完整查询的一部分运行时的相同逻辑:
颜色对应于两个屏幕截图中的相同表格。对于慢查询,OracleMERGE JOIN在JOIN. 结果,大约有 1.5 亿个中间行被不必要地处理。
我可以通过查询提示或重写来解决这个问题,但我想尽可能多地了解根本原因,以便将来避免这个问题,并可能向 Oracle 提交错误报告。每次我得到糟糕的计划UNPIVOT时,查询文本中的内容都会转换为UNION ALL计划中的一个。为了进一步调查,我想防止该查询转换发生。我一直找不到这个转换的名字。我也找不到可以阻止它的查询提示或下划线参数。我正在开发服务器上进行测试,所以一切顺利。
有什么我可以做,以防止的查询转换UNPIVOT到UNION ALL?我在 Oracle 12.1.0.2 上。
由于 IP 原因,我无法共享查询、表名或数据。我无法想出一个简单的复制品。话虽如此,我不清楚为什么需要这些信息来回答这个问题。下面是 UNPIVOT 查询的示例以及作为 UNION ALL 实现的相同查询。
看看这个查询。它非常简单(有关表和索引定义以及重现脚本,请参见文章末尾):
SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1 AND 1 = (SELECT 1);
Run Code Online (Sandbox Code Playgroud)
注意:“AND 1 = (SELECT 1) 只是为了防止此查询被自动参数化,我觉得这使问题变得混乱 - 尽管有或没有该子句,它实际上获得了相同的计划
这是计划(粘贴计划链接):
由于那里有一个“top 1”,我很惊讶地看到流聚合运算符。对我来说似乎没有必要,因为保证只有一行。
为了测试这个理论,我尝试了这个逻辑上等效的查询:
SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1
GROUP BY Id;
Run Code Online (Sandbox Code Playgroud)
这是那个计划(粘贴计划链接):
果然,group by 计划能够在没有流聚合操作符的情况下通过。
请注意,两个查询都从索引的末尾“向后”读取并执行“前 1”以获得最大修订。
我在这里缺少什么? 流聚合是否在第一个查询中真正起作用,还是应该能够消除它(这只是优化器的一个限制,它不是)?
顺便说一下,我意识到这不是一个非常实际的问题(两个查询都报告 0 毫秒的 CPU 和经过时间),我只是对这里展示的内部/行为感到好奇。
这是我在运行上述两个查询之前运行的设置代码:
DROP TABLE IF EXISTS dbo.TheOneders;
GO
CREATE TABLE dbo.TheOneders
(
Id INT NOT NULL,
Revision SMALLINT NOT NULL,
Something NVARCHAR(23),
CONSTRAINT PK_TheOneders PRIMARY KEY NONCLUSTERED …Run Code Online (Sandbox Code Playgroud) sql-server aggregate database-internals group-by sql-server-2017
我正在针对 SQL Server 2019 CU14 进行测试。我有一个纯行模式查询,它从复杂的视图中选择前 50 行。完整查询在 MAXDOP 1 时需要 25426 毫秒的 CPU 时间,在 MAXDOP 2 时需要 19068 毫秒的 CPU 时间。并行查询总体上使用较少的 CPU 时间并不令我感到惊讶。并行查询适用于位图运算符,并且查询计划在一些方面有所不同。然而,令我惊讶的是前 N 个排序的操作员时间的巨大差异。
在串行计划中,根据运算符执行统计数据,前 N 个排序占用了大约 10 秒的 CPU 时间:
MAXDOP 2 计划报告相同的前 N 排序大约需要 1.6 秒的 CPU 时间:
我不明白为什么两个不同的查询计划之间会报告如此大的差异。父运算符中的计算标量非常简单,无法解释运算符时间的差异。它们是这样的:
[Expr1055] = Scalar Operator(CASE WHEN COLUMN_1 IS NULL THEN (0) ELSE datediff(day,COLUMN_1,getdate()) END),
[Expr1074] = Scalar Operator(CASE WHEN [Expr1074] IS NULL THEN (0) ELSE [Expr1074] END)
Run Code Online (Sandbox Code Playgroud)
计划的不同部分还有其他计算标量。我上传了匿名的实际计划如果有人想查看的话,
当我将不带 TOP 的完整查询结果加载到临时表中并对临时表执行 TOP 50 排序时,并行计划和串行计划都需要大约 1200 毫秒的 …
该文档的sys.dm_exec_query_stats状态如下:
如果服务器上当前正在执行工作负载,则对 sys.dm_exec_query_stats 的初始查询可能会产生不准确的结果。可以通过重新运行查询来确定更准确的结果。
我有时会在活动工作负载期间查询该 DMV,并希望获得准确的结果。我不知道如何在实践中应用上述警告。我是否应该始终查询 DMV 两次并使用第二个结果集,因为这样会更准确?这感觉有点牵强。我是否需要了解 DMV 可能不准确的方式,以便我可以将其纳入分析?如果是这样,会出现什么类型的错误:丢失的行、过时的值、不一致的行或其他什么?
sys.dm_exec_query_stats在活动工作负载期间使用时的最佳做法是什么?
sp_whoisactive第一次在服务器上运行时,我遇到了一些意想不到的事情:
两场比赛已经持续了13天,但两场比赛似乎都在互相阻碍。看看sys.dm_tran_locks:
阻止进程阈值设置的配置值为 10 秒。其他死锁正在通过死锁监视器在服务器上成功解决。
来自参数的信息@get_locks:
<Database name="DB1">
<Locks>
<Lock request_mode="S" request_status="GRANT" request_count="1" />
</Locks>
<Objects>
<Object name="TBL1" schema_name="dbo">
<Locks>
<Lock resource_type="OBJECT" request_mode="IX" request_status="GRANT" request_count="1" />
<Lock resource_type="PAGE" page_type="*" index_name="PK__TBL1__3214EC27326C5B6A" request_mode="U" request_status="GRANT" request_count="1" />
<Lock resource_type="PAGE" page_type="*" index_name="PK__TBL1__3214EC27326C5B6A" request_mode="U" request_status="WAIT" request_count="1" />
</Locks>
</Object>
</Objects>
</Database>
<Database name="DB1">
<Locks>
<Lock request_mode="S" request_status="GRANT" request_count="1" />
</Locks>
<Objects>
<Object name="TBL2" schema_name="dbo">
<Locks>
<Lock resource_type="OBJECT" request_mode="Sch-S" request_status="GRANT" request_count="2" />
</Locks>
</Object>
<Object name="TBL1" schema_name="dbo">
<Locks>
<Lock resource_type="OBJECT" request_mode="IX" …Run Code Online (Sandbox Code Playgroud) SQL Server 2016添加了AT TIME ZONE运算符。从文档中:
\n\nAT TIME ZONE 实现依赖于 Windows 机制来跨时区转换日期时间值。
\n
AT TIME ZONEmscorlib.ni!TimeZoneInfo.ConvertTime根据针对简单查询的 ETW 跟踪调用该方法。乔纳森·凯哈亚斯 (Jonathan Kehayias) 发表了一篇博文,其中他从课堂上提取了所有时区规则System.TimeZoneInfo。我只能在输出中找到于 01/01/2004 或更高版本生效的规则:
Rob Farley 在一篇博客文章中提到,2000 年时区规则的更改似乎并未得到遵守AT TIME ZONE:
\n\n它通过使用 Windows 注册表来工作,其中包含所有这些信息,但遗憾的是,当回顾过去时,它\xe2\x80\x99 并不完美。澳大利亚于 2008 年更改了日期,美国于 2005 年更改了日期 \xe2\x80\x93 两国都在一年中的大部分时间实行夏令时。AT TIME ZONE 明白这一点。但它似乎并没有意识到,2000年的澳大利亚,由于悉尼奥运会,澳大利亚提前了大约两个月开始实行夏令时。
\n
我觉得有大量间接证据表明,AT TIME ZONE对于早于 2004 年的日期,操作员可能会返回不准确的结果。但是,我找不到任何AT TIME ZONE使用该类的文档System.TimeZoneInfo,这些文档AT TIME ZONE对于较旧的日期可能不准确,或者 …
考虑以下查询,该查询对少量标量聚合进行了反透视:
SELECT A, B
FROM (
SELECT
MAX(CASE WHEN ID = 1 THEN 1 ELSE 0 END) VAL1
, MAX(CASE WHEN ID = 2 THEN 1 ELSE 0 END) VAL2
, MAX(CASE WHEN ID = 3 THEN 1 ELSE 0 END) VAL3
, MAX(CASE WHEN ID = 4 THEN 1 ELSE 0 END) VAL4
, MAX(CASE WHEN ID = 5 THEN 1 ELSE 0 END) VAL5
, MAX(CASE WHEN ID = 6 THEN 1 ELSE 0 END) VAL6
, MAX(CASE …Run Code Online (Sandbox Code Playgroud) 我正在 SQL Server 2019 CU14 上进行测试。考虑针对兼容级别为 130 或 140 的 SQL Server 数据库创建的以下表值函数:
-- requires database compat 130 or 140 to see the issue
CREATE OR ALTER FUNCTION [dbo].[TVF_BUG_REPRO_2] (@O DateTime, @Z varchar(50))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
SELECT
CAST(
CASE
WHEN SZ.Zone1 > '' THEN (@O at time zone SZ.Zone1) at time zone 'Pacific Standard Time'
WHEN LEN(@Z) > 3 THEN (@O at time zone @Z) at time zone 'Pacific Standard Time'
ELSE @O
END AS DATETIME
) …Run Code Online (Sandbox Code Playgroud) BIT列在聚集列存储索引中使用时是否提供任何性能优势?例如,我对在 CCI 中定义列BIT而不是 所获得的任何性能优势感兴趣BIGINT。我正在使用 SQL Server 2016。
我对 CCI 压缩的工作原理知之甚少,但根据我所阅读的内容和一些测试,似乎数据类型(仅限于存储整数的精确数字)在列存储压缩方面确实无关紧要. 例如,如果我将 10 个完整的行组插入到带有BIGINT列而不是BIT列的表中,我看不到压缩行组之间的大小差异。以下是一项测试的源数据:
DROP TABLE IF EXISTS dbo.CCI_BIT_TEST_SOURCE;
CREATE TABLE dbo.CCI_BIT_TEST_SOURCE (
ID1 BIGINT NOT NULL,
ID2 BIGINT NOT NULL,
ID_BIT BIT NOT NULL,
ID_BIGINT BIGINT NOT NULL,
INDEX CCI__CCI_BIT_TEST_SOURCE CLUSTERED COLUMNSTORE
);
INSERT INTO dbo.CCI_BIT_TEST_SOURCE WITH (TABLOCK)
SELECT
t.RN
, t.RN
, t.RN % 2
, t.RN % 2
FROM
(
SELECT TOP (10485760) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) …Run Code Online (Sandbox Code Playgroud) sql-server ×9
parallelism ×2
aggregate ×1
columnstore ×1
deadlock ×1
dmv ×1
functions ×1
group-by ×1
oracle ×1
oracle-12c ×1
performance ×1
timezone ×1
union ×1
unpivot ×1