当使用系统版本控制的时态表(SQL Server 2016 中的新功能)时,当使用此功能处理大型关系数据仓库中的缓慢变化维度时,查询创作和性能影响是什么?
例如,假设我有一个Customer
带有Postal Code
列的 100,000 行维度和一个Sales
带有CustomerID
外键列的数十亿行事实表。并假设我想查询“按客户邮政编码划分的 2014 年总销售额”。简化的 DDL 是这样的(为了清楚起见省略了很多列):
CREATE TABLE Customer
(
CustomerID int identity (1,1) NOT NULL PRIMARY KEY CLUSTERED,
PostalCode varchar(50) NOT NULL,
SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL,
SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
)
WITH (SYSTEM_VERSIONING = ON);
CREATE TABLE Sale
(
SaleId int identity(1,1) NOT NULL PRIMARY KEY CLUSTERED,
SaleDateTime …
Run Code Online (Sandbox Code Playgroud) data-warehouse sql-server slowly-changing-dimension temporal-tables sql-server-2016
在诊断基数估计不佳的 SQL Server 2008 R2 查询(尽管有简单的索引、最新的统计数据等)和查询计划不佳时,我发现了一篇可能相关的知识库文章: FIX:运行查询时性能不佳包含 SQL Server 2008 或 SQL Server 2008 R2 或 SQL Server 2012 中的关联 AND 谓词
我可以猜测知识库文章中“相关”的含义,例如谓词#2 和谓词#1 主要针对相同的行。
但我不知道 SQL Server 是如何知道这些相关性的。表是否需要包含来自两个谓词的列的多列索引?SQL 是否使用统计信息来检查一列中的值是否与另一列相关?还是使用了其他方法?
我问这个有两个原因:
performance sql-server statistics sql-server-2008-r2 query-performance
将主表连接到详细表时,如何鼓励 SQL Server 2014 使用较大(详细)表的基数估计作为连接输出的基数估计?
例如,当将 10K 主行连接到 100K 详细行时,我希望 SQL Server 估计连接为 100K 行——与估计的详细行数相同。我应该如何构建我的查询和/或表和/或索引以帮助 SQL Server 的估算器利用每个详细信息行始终具有相应的主行这一事实?(这意味着它们之间的连接永远不应该减少基数估计。)
这里有更多细节。我们的数据库有一对主/明细表:VisitTarget
每个销售交易占一行,每个交易VisitSale
中的每个产品占一行。这是一个一对多的关系:一个 VisitTarget 行平均有 10 个 VisitSale 行。
表格如下所示:(我正在简化为仅针对此问题的相关列)
-- "master" table
CREATE TABLE VisitTarget
(
VisitTargetId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
SaleDate date NOT NULL,
StoreId int NOT NULL
-- other columns omitted for clarity
);
-- covering index for date-scoped queries
CREATE NONCLUSTERED INDEX IX_VisitTarget_SaleDate
ON VisitTarget (SaleDate) INCLUDE (StoreId /*, ...more columns */);
-- …
Run Code Online (Sandbox Code Playgroud) sql-server execution-plan sql-server-2014 cardinality-estimates
我在 SQL Server 2008 中将一个小表(1,000 行)与一个大表(8M 行)连接起来。连接使用大表上的非聚集覆盖索引,连接可以产生三种可能的查询计划。我试图找出哪个计划更好,但我也想概括这些知识,以便下次我可以更好地了解在查看 SQL I/O 统计信息时使用什么启发式方法。
计划 #1 是一个循环连接,并为大表发出统计信息,如下所示:
Scan count 2582, logical reads 35686, physical reads 1041, read-ahead reads 23052
Run Code Online (Sandbox Code Playgroud)
计划 #2 是一个合并连接并发出如下统计信息:
Scan count 1, logical reads 59034, physical reads 49, read-ahead reads 59004
Run Code Online (Sandbox Code Playgroud)
计划 #3 是一个散列连接并发出如下统计信息:
Scan count 3, logical reads 59011, physical reads 5, read-ahead reads 59010
Run Code Online (Sandbox Code Playgroud)
覆盖索引按 排序(ID, Date)
。查询返回大约 50% 的 ID 的数据,并且对于每个 ID,返回最近 3 个月数据的连续块,通常大约为每个 ID 的 1/4 或行。该查询返回索引中大约 1/8 的总行数。换句话说,查询是稀疏的,但始终如此。
我的假设是,计划 #1 对这种工作负载很糟糕,因为将磁盘磁头移动 2,500 次(甚至 1,041 次)比顺序磁盘扫描要昂贵得多。我还假设#3 …
在SQL服务器2014的基数估算白皮书说:
但是,新的 CE 使用更简单的算法,该算法假定大表和小表之间存在一对多连接关联。这假设大表中的每一行都与小表中的一行完全匹配。该算法返回较大输入的估计大小作为连接基数。
但它没有说明 SQL Server 如何确定什么是“大表”和“小表”以进行优化。
这些标准是否记录在任何地方?它是一个简单的阈值(例如“小表”必须低于 10,000 行)、百分比(例如“小表”必须小于“大表”中行的 5%),还是一些更复杂的函数?
此外,是否有跟踪标志或查询提示强制使用此优化进行特定连接?
最后,这个优化是否有一个可以用于进一步谷歌搜索的名称?
我问是因为我希望在主/明细表的连接中使用这种“使用大表的基数”基数估计行为,但是我的“小表”(主)是 1M 行,而我的“大表”(细节)是 22M 行。因此,我正在尝试了解有关此优化的更多信息,以查看是否可以调整我的查询以强制使用它。
在 SQL Server 2008 R2 中,我在具有 1 亿多行的多个表上有一个非聚集覆盖索引。该表有几千个“插入点”,所有新插入都在其中发生。这意味着无论填充因子如何,我很快就会在每个插入点处出现页面拆分和碎片,并且表格中的其他任何地方都不会出现碎片或拆分。不幸的是,查询总是包含新行,因此索引的碎片区域。
这是有关该问题的更多信息。索引都看起来像这种模式(为了清楚起见,下面进行了简化):
CREATE TABLE Foo (
id int identity(1,1) PRIMARY KEY CLUSTERED,
foreign_key int,
log_time datetime,
...)
CREATE NONCLUSTERED INDEX on Foo (foreign_key, log_time) INCLUDE (...)
Run Code Online (Sandbox Code Playgroud)
此表上的查询始终采用以下形式:
WHERE log_time > getdate()-70 AND foreign_key IN (select ...)
Run Code Online (Sandbox Code Playgroud)
其他事实:
IN
过滤器通常包括10%-50%foreign_key
的值的行和日期过滤器包括20%-40的行的%。平均值约为所选行总数的 15%。假设我在 SQL Server 2014 中有这两个查询,它们都从不相关的表中返回一行:
SELECT SUM(A) A, SUM(B) B FROM X
SELECT SUM(C) C, SUM(D) D FROM Y
Run Code Online (Sandbox Code Playgroud)
我想将这些查询组合成一个包含A, B, C, D
.
在单个查询中执行此操作的好方法是什么,而不是像在标量变量中选择结果这样的多查询解决方案?