标签: database-internals

为什么这个流聚合是必要的?

看看这个查询。它非常简单(有关表和索引定义以及重现脚本,请参见文章末尾):

SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1 AND 1 = (SELECT 1);
Run Code Online (Sandbox Code Playgroud)

注意:“AND 1 = (SELECT 1) 只是为了防止此查询被自动参数化,我觉得这使问题变得混乱 - 尽管有或没有该子句,它实际上获得了相同的计划

这是计划(粘贴计划链接)

使用流 agg 进行计划

由于那里有一个“top 1”,我很惊讶地看到流聚合运算符。对我来说似乎没有必要,因为保证只有一行。

为了测试这个理论,我尝试了这个逻辑上等效的查询:

SELECT MAX(Revision)
FROM dbo.TheOneders
WHERE Id = 1
GROUP BY Id;
Run Code Online (Sandbox Code Playgroud)

这是那个计划(粘贴计划链接):

没有流 agg 的计划

果然,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

12
推荐指数
1
解决办法
691
查看次数

防止由于空闲工作线程修剪而导致 THREADPOOL 等待

在阅读了 Josh Darnell 的Unusual THREADPOOL Waits之后,一位 Twitter 用户提到有一个未记录的跟踪标志可以防止修剪空闲工人

鸣叫

这个想法是,一旦 SQL Server 创建了足够的线程来为峰值工作负载提供服务,它就不应该在 15 分钟左右的不需要的工作线程之后修剪工作线程(将它们释放到操作系统)。

空闲的工作线程将继续使用资源(例如内存),但是THREADPOOL当突然需要更多工作线程时,不会出现等待的爆发。显然,这在使用 Always On 可用性组时会有所帮助。

这个未记录的跟踪标志是什么,它是如何工作的?

sql-server database-internals wait-types trace-flags

12
推荐指数
1
解决办法
450
查看次数

为什么禁用聚集索引会使表无法访问?

当索引被禁用时,定义保留在系统目录中但不再使用。SQL Server 不维护索引(因为表中的数据发生变化),并且索引不能用于满足查询。如果禁用聚集索引,则整个表将无法访问。

为什么不能直接从丢弃 B 树的表中访问数据?(最有可能通过逐行扫描表格)这比使数据完全无法访问更合适吗?

这是一个纯粹的理论问题 - 我永远不会真正这样做。这不是一个场景,也不是一个待办事项,我只是想知道为什么事情会这样,将其视为一个内部问题。

sql-server clustered-index database-internals

11
推荐指数
1
解决办法
1万
查看次数

高 PAGELATCH_* 和 WRITELOG 等待。他们有关系吗?

我们看到非常高的 PAGELATCH_EX 和 PAGELATCH_SH 等待类型以及高 WRITELOG 等待。我已经诊断出导致 PAGELATCH 等待的查询,并且可以通过降低插入到使用 IDENTITY 值定义的繁忙集群主键的插入率来消除它们。我知道这种现象被称为最后一页插入闩锁争用。

但是我的问题是,当插入新记录时,SQL Server 是否在缓冲页上取独占 PAGELATCH_EX,将记录​​插入缓冲页,将记录写入事务日志,然后按详细https://释放独占 PAGELATCH_EX www.microsoft.com/en-ie/download/details.aspx?id=26665 Page 24. 还是先将记录写入事务日志,然后再将 PAGELATCH_EX 作为详细的“Resolving PAGELATCH Contention on High Concurrent”INSERT Workloads -背景信息SQLCAT 的指南:关系引擎

如果记录是在闩锁机制之外写入日志,那么我可以排除由于高 PAGELATCH 等待而导致的缓慢写入磁盘的情况。但是,如果锁存器一直保持到记录被强化记录,那么我可能应该考虑 WRITELOG。

也有多个非聚集索引会导致 PAGELATCH_* 锁存器保持更长时间,即如果一个表有一个聚集和多个非聚集索引,同时向每个索引缓冲区页添加和释放锁存器?

更新 1 阅读confio-sql-server-writelog-wait幻灯片二和一般 WAL 架构后。我现在了解到,两份白皮书中详述的“记录该行已被修改的日志条目”步骤是指 SQL Server 记录事务日志缓存中的更改,而不是磁盘。一旦事务完成或缓冲区已满,所有记录都会立即刷新到磁盘。

sql-server sql-server-2008-r2 database-internals sql-server-2012 sql-server-2014

11
推荐指数
1
解决办法
1522
查看次数

与 sys.allocation_units 中的表大小不匹配的 DATALENGTH 总和

我的印象是,如果我要对DATALENGTH()表中所有记录的所有字段求和,我将得到表的总大小。我错了吗?

SELECT 
SUM(DATALENGTH(Field1)) + 
SUM(DATALENGTH(Field2)) + 
SUM(DATALENGTH(Field3)) TotalSizeInBytes
FROM SomeTable
WHERE X, Y, and Z are true
Run Code Online (Sandbox Code Playgroud)

我在下面使用了这个查询(我从网上得到的表大小,聚集索引,所以它不包括 NC 索引)来获取我的数据库中特定表的大小。出于计费目的(我们按部门使用的空间量收费),我需要计算出每个部门在此表中使用了多少空间。我有一个查询来标识表中的每个组。我只需要弄清楚每个组占用了多少空间。

由于VARCHAR(MAX)表中的字段,每行的空间可能会剧烈波动,所以我不能只取平均大小 * 部门的行数比率。当我使用上述DATALENGTH()方法时,我只能获得下面查询中使用的总空间的 85%。想法?

SELECT 
s.Name AS SchemaName,
t.NAME AS TableName,
p.rows AS RowCounts,
(SUM(a.total_pages) * 8)/1024 AS TotalSpaceMB, 
(SUM(a.used_pages) * 8)/1024 AS UsedSpaceMB, 
((SUM(a.total_pages) - SUM(a.used_pages)) * 8)/1024 AS UnusedSpaceMB
FROM 
    sys.tables t with (nolock)
INNER JOIN 
    sys.schemas s with (nolock) ON s.schema_id = t.schema_id
INNER JOIN      
    sys.indexes i with (nolock) ON t.OBJECT_ID …
Run Code Online (Sandbox Code Playgroud)

sql-server data-pages clustered-index metadata database-internals

11
推荐指数
2
解决办法
3870
查看次数

可以参与 SET 操作的局部变量的最大数量是多少?

我有一个包含业务逻辑的存储过程。在它里面我有大约 1609 个变量(不要问我为什么,这就是引擎的工作原理)。我尝试将SET一个变量连接到所有其他变量的连接值。结果在创建过程中出现错误:

消息 8631,级别 17,状态 1,过程 XXX,行 YYY 内部错误:已达到服务器堆栈限制。请在您的查询中寻找潜在的深层嵌套,并尝试简化它。

我发现错误是由于我需要在SET操作中使用的变量数量。我可以通过将其一分为二来执行任务。

我的问题是这方面有一些限制吗?我查了查,但没有找到。

我们检查了此 KB 中描述的错误,但这不是我们的情况。我们不在CASE代码中使用任何表达式。我们使用该临时变量来准备必须使用 CLR 函数替换的值列表。我们将 SQL Server 更新为 SP3 CU6(最新的),但我们仍然遇到错误。

sql-server t-sql database-internals sql-server-2012 errors

11
推荐指数
2
解决办法
2783
查看次数

为什么嵌套循环连接只支持左连接?

在 Craig Freedman 的博客Nested Loops Join 中,他解释了为什么嵌套循环联接不能支持右外联接

问题是我们多次扫描内表——外连接的每一行扫描一次。在这些多次扫描期间,我们可能会多次遇到相同的内部行。在什么时候我们可以得出结论,特定的内部行没有或不会加入?

有人可以用一种非常简单和有教育意义的方式解释一下吗?

这是否意味着循环从外表 ( R1) 开始并扫描内表 ( R2)?

我知道对于R1不与 连接的值,R2应将其替换为 aNULL以便结果集变为 ( NULL, R2)。对我来说,R2R1不加入时似乎不可能返回一个值,因为它不知道R2要返回哪个值。但这不是它的解释方式。或者是吗?

SQL Server会在事实上优化(经常替换)RIGHT JOINLEFT JOIN,但问题是解释为什么它在技术上是不可能的NESTED LOOPS JOIN使用/支持RIGHT JOIN逻辑。

join sql-server database-internals

11
推荐指数
2
解决办法
1525
查看次数

列出特定表的 ROW_OVERFLOW_DATA 页

我正在尝试获取具有 ROW_OVERFLOW_DATA 行的表的页面列表。我可以从未记录的 DMV 获取已分配页面的列表sys.db_db_database_page_allocations,但是,该 DMV 的输出中似乎没有列出 ROW_OVERFLOW_DATA 页面。是否还有其他一些我根本找不到的 DMV?

最小、完整且(希望如此!)可验证的示例:

USE tempdb;

IF OBJECT_ID(N'dbo.t', N'U') IS NOT NULL
DROP TABLE dbo.t;
GO

CREATE TABLE dbo.t
(
    rownum int NOT NULL IDENTITY(1,1)
        PRIMARY KEY CLUSTERED
    , on_row_data varchar(30) NOT NULL
        DEFAULT ('on_row_data')
    , off_row_data varchar(MAX) NOT NULL
        DEFAULT REPLICATE('A', 20000) --PLENTY BIG ENOUGH!
) WITH (DATA_COMPRESSION = NONE); --not compressing those pages!

INSERT INTO dbo.t DEFAULT VALUES;

DECLARE @ObjectID int = (SELECT o.object_id FROM sys.objects o WHERE o.name …
Run Code Online (Sandbox Code Playgroud)

sql-server database-internals

11
推荐指数
1
解决办法
239
查看次数

加入的虚拟表中的 NEWID() 导致意外的交叉应用行为

我的实际工作查询是内部联接,但是这个带有交叉联接的简单示例似乎几乎总是会重现该问题。

SELECT *
FROM (
    SELECT 1 UNION ALL
    SELECT 2
) AA ( A )
CROSS JOIN (
    SELECT NEWID() TEST_ID
) BB ( B )
Run Code Online (Sandbox Code Playgroud)

通过我的内部连接,我有很多行,我使用 NEWID() 函数为每个行添加了一个 GUID,对于大约 10 个这样的行中的 9 个,与 2 行虚拟表的乘法产生了预期的结果,只有 2 个副本相同的 GUID,而十分之一会产生不同的结果。至少可以说这是出乎意料的,让我很难在我的测试数据生成脚本中找到这个错误。

如果您使用非确定性 getdate 和 sysdatetime 函数查看以下查询,您将看不到这一点,无论如何我都看不到 - 我总是在两个最终结果行中看到相同的日期时间值。

SELECT *
FROM (
    SELECT 1 UNION ALL
    SELECT 2
) AA ( A )
CROSS JOIN (
    SELECT GETDATE() TEST_ID
) BB ( B )

SELECT *
FROM (
    SELECT 1 UNION …
Run Code Online (Sandbox Code Playgroud)

sql-server-2008 sql-server database-internals

10
推荐指数
1
解决办法
1658
查看次数

哈希聚合救助

在聊天讨论中出现的一个问题:

我知道散列连接救助在内部切换到某种嵌套循环。

SQL Server 为散列聚合救助做了什么(如果它可以发生的话)?

sql-server aggregate execution-plan database-internals hashing

10
推荐指数
1
解决办法
381
查看次数