我正在测试从聚集列存储索引中删除数据。
我注意到执行计划中有一个很大的eager spool操作符:
这完成了以下特征:
如果我欺骗估算器低估,我会得到一个更快的计划,避免使用 TempDB:
预计扫描成本:56.901
(这是一个估计的计划,但评论中的数字是正确的。)
有趣的是,如果我通过运行以下命令刷新增量存储,线轴会再次消失:
ALTER INDEX IX_Clustered ON Fact.RecordedMetricsDetail REORGANIZE WITH (COMPRESS_ALL_ROW_GROUPS = ON);
Run Code Online (Sandbox Code Playgroud)
只有当增量存储中的页面超过某个阈值时才会引入假脱机。
为了检查增量存储的大小,我正在运行以下查询来检查表的行内页:
SELECT
SUM([in_row_used_page_count]) AS in_row_used_pages,
SUM(in_row_data_page_count) AS in_row_data_pages
FROM sys.[dm_db_partition_stats] as pstats
JOIN sys.partitions AS p
ON pstats.partition_id = p.partition_id
WHERE p.[object_id] = OBJECT_ID('Fact.RecordedMetricsDetail');
Run Code Online (Sandbox Code Playgroud)
第一个计划中的假脱机迭代器是否有任何合理的好处?我不得不假设它是为了提高性能而不是为了万圣节保护,因为它的存在不一致。
我正在 2016 CTP 3.1 上对此进行测试,但我在 2014 SP1 CU3 上看到了相同的行为。
我已经发布了一个生成模式和数据的脚本,并指导您在此处演示问题。
这个问题主要是出于对优化器此时行为的好奇,因为我有一个解决方法来解决引发这个问题的问题(一个大的 spool 填充了 TempDB)。我现在通过使用分区切换来删除。
我再次发现 SQL Server 和 MERGE 语句存在问题,需要进行一些确认。
我可以在 Azure 数据库上不断重现我的问题(但不能在本地 SQL Server 2017/2019 上重现)。
请执行以下步骤(一步一步,而不是一次命令执行)!
1)架构脚本:
CREATE TABLE [dbo].[ImpactValueHistory]
(
[Rn] BIGINT NOT NULL,
[ImpactId] UNIQUEIDENTIFIER NOT NULL,
[ImpactValueTypeId] INT NOT NULL,
[Date] DATE NOT NULL,
[Value] DECIMAL(38, 10) NOT NULL,
[ValidFrom] DATETIME2 NOT NULL CONSTRAINT [DF_ImpactValueHistory_ValidFrom] DEFAULT CONVERT(DATETIME2, '0001-01-01'),
[ValidTo] DATETIME2 NOT NULL CONSTRAINT [DF_ImpactValueHistory_ValidTo] DEFAULT CONVERT(DATETIME2, '9999-12-31 23:59:59.9999999'),
[ImpactPeriodId] INT NOT NULL,
[NormalizedValue] DECIMAL(38, 10) NOT NULL,
)
GO
CREATE CLUSTERED COLUMNSTORE INDEX [COLIX_ImpactValueHistory]
ON [dbo].[ImpactValueHistory];
GO
CREATE NONCLUSTERED …Run Code Online (Sandbox Code Playgroud) 在查询中使用列存储索引时,SQL Server 能够使用批处理模式。关于什么可以在批处理模式下运行,什么不能运行的文档很少。请查看以下(激励性)查询计划,其中以批处理模式(绿色)执行的事情数量惊人:

(这是一个估计的计划,我用实际计划来验证实际执行方式确实是批处理。)
请注意,只有 T1 的构建端使用列存储索引。所有探测输入(T2 和 T3)都是行存储。他们的数据似乎过渡到批处理模式。我一直认为批处理模式仅用于通过探针端运行的数据流。
即使数据不是来自列存储索引,数据似乎也可以转换为批处理模式。这就提出了一个问题:为什么 SQL Server 不对仅行存储的查询使用批处理模式?可能对他们中的一些人有益。使用列存储索引是否是使 SQL Server 考虑批处理模式所必需的正式要求?我们可以添加一个带有列存储索引的零行虚拟表来引入批处理模式并实现性能提升吗?
从 SQL Server 2014 开始,究竟可以在批处理模式下运行什么?
SQL Server 2012 中代号Denali为Columnstore 索引的新功能之一。
我对常规的旧行存储索引非常了解,例如 b 树结构、叶级和 b 树页面之间的存储差异、包含字段的影响、优化使用它们、键的顺序等。
我很难获得有关列存储索引内部结构的任何好的信息。
我能找到的很多关于它们的信息基本上与“正常”索引完全相反,即没有键的排序,没有包含的字段,只有非聚集。
任何见解表示赞赏。
我昨天在查询时遇到了一些性能问题,经过进一步调查,我注意到我认为我试图深入了解聚集列存储索引的奇怪行为。
该表是
CREATE TABLE [dbo].[NetworkVisits](
[SiteId] [int] NOT NULL,
[AccountId] [int] NOT NULL,
[CreationDate] [date] NOT NULL,
[UserHistoryId] [int] NOT NULL
)
Run Code Online (Sandbox Code Playgroud)
与索引:
CREATE CLUSTERED COLUMNSTORE INDEX [CCI_NetworkVisits]
ON [dbo].[NetworkVisits] WITH (DROP_EXISTING = OFF, COMPRESSION_DELAY = 0) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
该表目前有 13 亿行,我们不断向其中插入新行。当我说不断时,我的意思是一直。这是一次向表中插入一行的稳定流程。
Insert Into NetworkVisits (SiteId, AccountId, CreationDate, UserHistoryId)
Values (@SiteId, @AccountId, @CreationDate, @UserHistoryId)
Run Code Online (Sandbox Code Playgroud)
执行计划在这里
我还有一个每 4 小时运行一次的预定作业,用于从表中删除重复的行。查询是:
With NetworkVisitsRows
As (Select SiteId, UserHistoryId, Row_Number() Over (Partition By SiteId, UserHistoryId
Order By CreationDate Asc) RowNum
From NetworkVisits
Where CreationDate …Run Code Online (Sandbox Code Playgroud) 我正在使用索引对数据仓库进行性能调整。我对 SQL Server 2014 还是很陌生。Microsoft 描述了以下内容:
“我们将聚集列存储索引视为存储大型数据仓库事实表的标准,并预计它将用于大多数数据仓库场景。由于聚集列存储索引是可更新的,您的工作负载可以执行大量的插入、更新、和删除操作。” http://msdn.microsoft.com/en-us/library/gg492088.aspx
但是,如果您进一步阅读文档,您会发现限制和限制:
“不能有唯一约束、主键约束或外键约束。”
这让我很困惑!出于各种原因(数据完整性、语义层可见的关系......)
所以微软提倡数据仓库场景使用聚集列存储索引;但是,它不能处理外键关系?!
我在这方面正确吗?您会建议哪些其他方法?过去,我在数据仓库场景中使用了非聚集列存储索引,对数据加载进行删除和重建。然而,SQL Server 2014 并没有为数据仓库增加真正的新价值??
foreign-key data-warehouse sql-server columnstore sql-server-2014
当我注意到我的一些插入花费的时间比预期的要长时,我正在做一个涉及 CCI 的演示。要重现的表定义:
DROP TABLE IF EXISTS dbo.STG_1048576;
CREATE TABLE dbo.STG_1048576 (ID BIGINT NOT NULL);
INSERT INTO dbo.STG_1048576
SELECT TOP (1048576) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
DROP TABLE IF EXISTS dbo.CCI_BIGINT;
CREATE TABLE dbo.CCI_BIGINT (ID BIGINT NOT NULL, INDEX CCI CLUSTERED COLUMNSTORE);
Run Code Online (Sandbox Code Playgroud)
对于测试,我将从临时表中插入所有 1048576 行。只要它没有因某种原因被修剪,这就足以填充一个压缩的行组。
如果我插入所有整数 mod 17000,它需要不到一秒钟的时间:
TRUNCATE TABLE dbo.CCI_BIGINT;
INSERT INTO dbo.CCI_BIGINT WITH (TABLOCK)
SELECT ID % 17000
FROM dbo.STG_1048576
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)
SQL Server 执行时间:CPU 时间 = 359 …
在 SQL Server 中,行存储表上的非唯一非聚集索引在非聚集索引结构的所有级别合并了基础对象的书签(RID 或聚集键)。书签作为非聚集索引键的一部分存储在所有索引级别。
另一方面,如果非聚集索引是unique,则书签仅存在于索引的叶级别 - 不作为键的一部分(实际上,书签作为一个或多个包含的列存在)。
在 SQL Server 2016 中,可以在面向列的表(具有聚集列存储索引的表)上构建非聚集 b 树索引。
如果文件组包含列存储索引,则似乎设置文件组以read_only防止dbcc checkdb整个数据库。尝试运行checkdb或checkfilegroup(对于数据库中的任何文件组,包括读写辅助文件和[PRIMARY])时,将返回以下错误...
Msg 8921, Level 16, State 1, Line 24
Check terminated. A failure was detected while collecting facts.
Possibly tempdb out of space or a system table is inconsistent. Check previous errors.
Run Code Online (Sandbox Code Playgroud)
是否有支持在只读文件组中存储列存储数据的方法?还是在这种情况下我无法进行完整性检查?
create database check_fg_ro
go
use check_fg_ro
go
exec sp_changedbowner 'sa';
go
alter database check_fg_ro add filegroup check_fg_ro_2;
alter database check_fg_ro
add file (
name='check_fg_ro_2'
,filename='C:\check_fg_ro_2.ndf'
) to filegroup check_fg_ro_2;
go
create table …Run Code Online (Sandbox Code Playgroud) sql-server filegroups columnstore dbcc-checkdb read-only-database
我有一个包含约 2 亿行和约 15 列的表。我打算COLUMNSTORE在我的表上创建一个索引。
根据我在列存储索引中使用的列顺序,性能是否会有任何变化?如果是,其背后的逻辑是什么?
index database-design sql-server sql-server-2012 columnstore
columnstore ×10
sql-server ×9
index ×2
batch-mode ×1
dbcc-checkdb ×1
filegroups ×1
foreign-key ×1
merge ×1