我试图了解 SQL Server 如何估计下面的 Stack Overflow 数据库查询的基数
首先,我创建索引
CREATE INDEX IX_PostId ON dbo.Comments
(
PostId
)
INCLUDE
(
[Text]
)
Run Code Online (Sandbox Code Playgroud)
这是查询:
SELECT u.DisplayName,
c.PostId,
c.Text
FROM Users u
JOIN Comments c
ON u.Reputation = c.PostId
WHERE u.AccountId = 22547
Run Code Online (Sandbox Code Playgroud)
执行计划在这里
首先,SQL Server 扫描用户表上的聚集索引以返回与 AccountId 谓词匹配的用户。我可以看到它使用了这个统计数据:_WA_Sys_0000000E_09DE7BCC
我可以看到该用户没有范围高键,因此 SQL Server 使用 avg_range 行并估计 1
评论索引搜索的搜索谓词是
soScalar Operator([StackOverflow2010].[dbo].[Users].[Reputation] as [u].[Reputation]表示users表中accountId为的用户的信誉值22547
我可以看到总共加载了三个统计数据:
_WA_Sys_0000000E_09DE7BCC- Users.AccountId(用于估计聚集索引查找谓词)
IX_PostId- Comments.PostId(用于估计索引查找谓词)
_WA_Sys_0000000A_09DE7BCC- 用户.声誉 (?)
SQL Server 如何得出索引查找的估计值?它无法在编译时知道 accountId 的信誉,22547因为帐户 …
sql-server execution-plan cardinality-estimates sql-server-2019
我有一个 SQL Server 查询如下(混淆):
UPDATE [TABLE1]
SET [COLUMN1] = CAST('N' AS CHAR(1))
FROM [TABLE1]
WHERE (COLUMN1 = '2' AND COLUMN2 IN('VAL1', 'VAL2', 'VAL3')) OR
(COLUMN1 <> 'N' AND (
SELECT COUNT(*)
FROM TABLE2 wle
JOIN TABLE3 wl
ON wl.COLUMN3 = wle.COLUMN3
WHERE TABLE1.COLUMN4 = wle.COLUMN4 AND
(wl.COLUMN5 = '1' OR wl.COLUMN6 = '1') AND
wle.COLUMN7 = (
SELECT MIN(alias.COLUMN7)
FROM TABLE2 AS alias
WHERE TABLE1.COLUMN4 = alias.COLUMN4
)
) > 0
)
Run Code Online (Sandbox Code Playgroud)
我们刚刚将我们的(测试)服务器从 SQL Server 2014 SP3 升级到 SQL Server …
给出下表:
CREATE TABLE #a
(
MyInt INT
)
INSERT INTO #a VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
CREATE TABLE #b
(
MyVarchar VARCHAR(10)
)
INSERT INTO #b VALUES('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'),('ten')
Run Code Online (Sandbox Code Playgroud)
如果我运行以下查询;
SELECT *
FROM #a
LEFT JOIN #b
ON #a.MyInt = #b.MyVarchar
Run Code Online (Sandbox Code Playgroud)
SQL Server 必须执行隐式转换,因为#a.MyInt和#b.MyVarchar是不匹配的数据类型。由于数据类型优先级,具有最低类型优先级 (#b.MyVarchar) 的列将转换为较高优先级 (INT) 的类型
这意味着上面的查询等效于
SELECT *
FROM #a
LEFT JOIN #b
ON #a.MyInt = CONVERT(INT,#b.MyVarchar)
Run Code Online (Sandbox Code Playgroud)
两者都失败,因为其中某个值#b.MyVarchar对于列来说是无效值INT。
我的问题是为什么 的VARCHAR优先级低于INT?如果是相反的情况,隐式转换将会成功,但我们会得到一个错误的查询。为什么错误比成功执行更可取?我的猜测是,这对于 SQL Server 来说更像是一种“防御”机制 - 它更喜欢错误,因此需要用户明确决定他们想要做什么,而不是在用户不知情的情况下给出可能意外的查询结果。意识到?
我的错误级别 16 警报设置如下:
USE [msdb]
GO
EXEC msdb.dbo.sp_add_alert @name=N'Error - Severity 16',
@message_id=0,
@severity=16,
@enabled=1,
@delay_between_responses=0,
@include_event_description_in=1,
@category_name=N'[Uncategorized]',
@job_id=N'00000000-0000-0000-0000-000000000000'
Run Code Online (Sandbox Code Playgroud)
我很好奇为什么
SELECT 1/0;
Run Code Online (Sandbox Code Playgroud)
消息 8134,级别 16,状态 1,第 17 行 遇到除零错误。
没有引发错误,但是
BACKUP DATABASE MyDatabase TO DISK = 'C:\FolderThatDoesntexist'
Run Code Online (Sandbox Code Playgroud)
消息 3201,级别 16,状态 1,第 8 行 无法打开备份设备“C:\FolderThatDoesntexist”。操作系统错误 5(访问被拒绝。)。
消息 3013,级别 16,状态 1,第 8 行备份数据库异常终止。
曾是
这篇文章和它引用的博客文章表明 SQL Server 只会针对记录的错误引发事件,这可以在sys.messages
所以我查询sys.messages了这些错误代码:
SELECT severity,
message_id,
is_event_logged
FROM sys.messages
WHERE language_id = 1033 AND
message_id IN (8134,3201,3013)
Run Code Online (Sandbox Code Playgroud)
但发现这三个都设置为0:
为什么 3201 …
我一直在对新的(虚拟)服务器进行一些测试,以替换现有的生产服务器。我们怀疑当前的生产服务器规格过高,因此正在从低水平调整新服务器的虚拟组件(RAM、CPU 等),直到性能适合处理当前的工作负载。
虽然认识到新服务器处理现有服务器工作负载的能力的真正测试是针对新服务器测试该工作负载,但出于兴趣,我对现有服务器和新服务器进行了一些简单的、任意的测试:
(两台服务器上使用相同的数据库备份,以使上述所有测试保持一致)
以上所有内容都支持新服务器(更快的读写速度、更快的 CHECKDB)
我做的最后一个基本测试是测试执行一个简单的操作所需的时间SELECT *在冷缓存和热缓存上最大的表之一上执行简单操作所需的时间,以进一步了解读取速度。
测试代码如下,我在两台服务器上运行
USE StackOverflow
SET STATISTICS IO, TIME ON
CHECKPOINT
DBCC DROPCLEANBUFFERS
SELECT * FROM Users /* cold cache run */
SELECT * FROM Users /* warm cache run */
Run Code Online (Sandbox Code Playgroud)
统计IO如下:
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 12 ms.
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
SQL Server Execution Times:
CPU time = …Run Code Online (Sandbox Code Playgroud) sql-server ×3
errors ×2
alerts ×1
buffer-pool ×1
datatypes ×1
memory ×1
parallelism ×1
performance ×1
raiserror ×1