这似乎是一个有很多神话和相互冲突的领域。
那么SQL Server中的表变量和本地临时表有什么区别呢?
鉴于以下组件
DECLARE @D DATE = '2013-10-13'
DECLARE @T TIME(7) = '23:59:59.9999999'
Run Code Online (Sandbox Code Playgroud)
将它们结合起来以产生DATETIME2(7)具有价值的结果的最佳方法是'2013-10-13 23:59:59.9999999'什么?
有些东西不工作,如下表所示。
SELECT @D + @T
Run Code Online (Sandbox Code Playgroud)
操作数数据类型日期对加法运算符无效。
SELECT CAST(@D AS DATETIME2(7)) + @T
Run Code Online (Sandbox Code Playgroud)
操作数数据类型 datetime2 对加法运算符无效。
SELECT DATEADD(NANOSECOND,DATEDIFF(NANOSECOND,CAST('00:00:00.0000000' AS TIME),@T),@D)
Run Code Online (Sandbox Code Playgroud)
datediff 函数导致溢出。分隔两个日期/时间实例的日期部分数量太大。尝试将 datediff 与不太精确的日期部分一起使用。
* 可以在 Azure SQL 数据库和 SQL Server 2016 中避免溢出,使用DATEDIFF_BIG.
SELECT CAST(@D AS DATETIME) + @T
Run Code Online (Sandbox Code Playgroud)
数据类型 datetime 和 time 在 add 运算符中不兼容。
SELECT CAST(@D AS DATETIME) + CAST(@T AS DATETIME)
Run Code Online (Sandbox Code Playgroud)
返回结果但失去精度
2013-10-13 23:59:59.997
这份 2007 年的白皮书比较了单个 select/insert/delete/update 和 range select 语句在组织为聚集索引的表上的性能与在与 CI 相同的键列上组织为具有非聚集索引的堆的表上的性能桌子。
一般来说,聚集索引选项在测试中表现更好,因为只有一种结构需要维护,而且不需要书签查找。
该论文未涵盖的一个潜在有趣案例是堆上的非聚集索引与聚集索引上的非聚集索引之间的比较。在那种情况下,我曾期望堆甚至可能表现得更好,因为一旦在 NCI 叶级 SQL Server 有一个 RID 可以直接跟随,而不需要遍历聚集索引。
有没有人知道在这个领域进行过类似的正式测试,如果有,结果是什么?
SELECT CAST (
REPLACE (
REPLACE (
XEventData.XEvent.value ('(data/value)[1]', 'varchar(max)'),
'<victim-list>', '<deadlock><victim-list>'),
'<process-list>', '</victim-list><process-list>')
AS XML) AS DeadlockGraph
FROM (SELECT CAST (target_data AS XML) AS TargetData
FROM sys.dm_xe_session_targets st
JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address
WHERE [name] = 'system_health') AS Data
CROSS APPLY TargetData.nodes ('//RingBufferTarget/event') AS XEventData (XEvent)
WHERE XEventData.XEvent.value('@name', 'varchar(4000)') = 'xml_deadlock_report';
Run Code Online (Sandbox Code Playgroud)
在我的机器上完成大约需要 20 分钟。报告的统计数据是
Table 'Worktable'. Scan count 0, logical reads 68121, physical reads 0, read-ahead reads 0,
lob logical reads 25674576, lob …Run Code Online (Sandbox Code Playgroud) xml sql-server execution-plan database-internals sql-server-2012
我正在查看此处的文章 Temporary Tables vs. Table Variables and their Effect on SQL Server Performance and on SQL Server 2008 能够重现与 2005 中显示的结果类似的结果。
当执行只有 10 行的存储过程(定义如下)时,表变量 version out 执行临时表 version 的两倍以上。
我清除了过程缓存并运行了两个存储过程 10,000 次,然后再重复该过程 4 次。结果如下(每批时间以毫秒为单位)
T2_Time V2_Time
----------- -----------
8578 2718
6641 2781
6469 2813
6766 2797
6156 2719
Run Code Online (Sandbox Code Playgroud)
我的问题是:表变量版本性能更好的原因是什么?
我做了一些调查。例如查看性能计数器
SELECT cntr_value
from sys.dm_os_performance_counters
where counter_name = 'Temp Tables Creation Rate';
Run Code Online (Sandbox Code Playgroud)
确认在这两种情况下,临时对象都按预期在第一次运行后被缓存,而不是每次调用都从头开始创建。
类似地跟踪Profiler 中的Auto Stats, SP:Recompile,SQL:StmtRecompile事件(下面的屏幕截图)显示这些事件仅发生一次(在第一次调用#temp表存储过程时),其他 9,999 次执行不会引发任何这些事件。(表变量版本没有得到任何这些事件) …
假设我有以下架构和数据:
create table images(
id int not null
);
insert into images values(1), (2), (3), (4), (6), (8);
Run Code Online (Sandbox Code Playgroud)
我想执行如下查询:
select id from images where id not exists in(4, 5, 6);
Run Code Online (Sandbox Code Playgroud)
但这不起作用。上面的情况应该返回5,因为它不存在于表记录中。
在下面的查询中,估计两个执行计划对唯一索引执行 1,000 次搜索。
查找是由对同一源表的有序扫描驱动的,因此看起来最终应该以相同的顺序查找相同的值。
两个嵌套循环都有 <NestedLoops Optimized="false" WithOrderedPrefetch="true">
任何人都知道为什么这个任务在第一个计划中的成本为 0.172434,而在第二个计划中为 3.01702?
(问题的原因是第一个查询被建议作为优化,因为计划成本明显低得多。它实际上在我看来好像它做了更多的工作,但我只是试图解释这种差异.. .)
CREATE TABLE dbo.Target(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL);
CREATE TABLE dbo.Staging(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL);
INSERT INTO dbo.Target
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1,
master..spt_values v2;
INSERT INTO dbo.Staging
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1;
Run Code Online (Sandbox Code Playgroud)
WITH T
AS (SELECT *
FROM Target AS T
WHERE T.KeyCol …Run Code Online (Sandbox Code Playgroud) 这是我定期遇到的一个问题,但尚未找到好的解决方案。
假设如下表结构
CREATE TABLE T
(
A INT PRIMARY KEY,
B CHAR(1000) NULL,
C CHAR(1000) NULL
)
Run Code Online (Sandbox Code Playgroud)
并且要求是确定可空列中的任何一个B或C实际上是否包含任何NULL值(如果是,则是哪个(些))。
还假设该表包含数百万行(并且没有可用的列统计信息可以查看,因为我对此类查询的更通用解决方案感兴趣)。
我可以想到几种方法来解决这个问题,但都有弱点。
两个单独的EXISTS声明。这将具有允许查询在NULL发现a 后尽早停止扫描的优点。但是如果两列实际上都不包含NULLs,那么将导致两次完整扫描。
单一聚合查询
SELECT
MAX(CASE WHEN B IS NULL THEN 1 ELSE 0 END) AS B,
MAX(CASE WHEN C IS NULL THEN 1 ELSE 0 END) AS C
FROM T
Run Code Online (Sandbox Code Playgroud)
这可以同时处理两列,因此最坏的情况是一次完整扫描。缺点是即使它NULL在查询的很早的时候在两列中都遇到了 a ,最终仍会扫描整个表的其余部分。
用户变量
我可以想到第三种方式来做到这一点
BEGIN TRY
DECLARE @B INT, @C INT, @D …Run Code Online (Sandbox Code Playgroud) DECLARE @T TABLE(
Col NCHAR(1));
INSERT INTO @T
VALUES (N'A'),
(N'B'),
(N'C'),
(N'?'),
(N'?'),
(N'?');
Run Code Online (Sandbox Code Playgroud)
SELECT *
FROM @T
WHERE Col LIKE N'%?%'
Run Code Online (Sandbox Code Playgroud)
Col
A
B
C
?
?
?
Run Code Online (Sandbox Code Playgroud)
SELECT *
FROM @T
WHERE Col = N'?'
Run Code Online (Sandbox Code Playgroud)
退货
Col
?
?
?
Run Code Online (Sandbox Code Playgroud)
使用下面的生成每个可能的双字节“字符”显示=版本匹配其中的 21,229 个和LIKE N'%?%'所有版本(我尝试了一些非二进制排序规则,结果相同)。
WITH T(I, N)
AS
(
SELECT TOP 65536 ROW_NUMBER() OVER (ORDER BY @@SPID),
NCHAR(ROW_NUMBER() OVER (ORDER BY @@SPID))
FROM master..spt_values v1,
master..spt_values v2
)
SELECT I, N
FROM …Run Code Online (Sandbox Code Playgroud) 正常的JOIN ... ON ...语法是众所周知的。但也可以将ON子句JOIN与其对应的分开放置。这在实践中很少见,在教程中找不到,我也没有找到任何网络资源甚至提到这是可能的。
这是一个可以玩的脚本:
SELECT *
INTO #widgets1
FROM (VALUES (1), (2), (3)) x(WidgetID)
SELECT *
INTO #widgets2
FROM (VALUES (1, 'SomeValue1'), (2, 'SomeValue2'), (3, 'SomeValue3')) x(WidgetID, SomeValue)
SELECT *
INTO #widgetProperties
FROM (VALUES
(1, 'a'), (1, 'b'),
(2, 'a'), (2, 'b'))
x(WidgetID, PropertyName)
--q1
SELECT w1.WidgetID, w2.SomeValue, wp.PropertyName
FROM #widgets1 w1
LEFT JOIN #widgets2 w2 ON w2.WidgetID = w1.WidgetID
LEFT JOIN #widgetProperties wp ON w2.WidgetID = wp.WidgetID AND wp.PropertyName = …Run Code Online (Sandbox Code Playgroud) sql-server ×9
t-sql ×2
datatypes ×1
date ×1
datetime2 ×1
like ×1
optimization ×1
performance ×1
postgresql ×1
time ×1
unicode ×1
xml ×1