上周我一直在做 MS10775A 课程,出现了一个培训师无法可靠回答的问题是:
重新索引会更新统计信息吗?
我们发现网上的讨论都在争论它有没有。
我继承了执行以下操作的维护计划:
在 23 分钟的维护计划中,更新统计数据需要惊人的 13 分钟。在这 13 分钟期间,对数据库的访问被阻止(或者至少,从这个数据库到我们其他数据库的复制被暂停)。
我的问题是:
我们应该什么时候更新统计数据,为什么?
这似乎是我们应该比每天少做的事情。我试图让我们摆脱“仅仅因为”进行不必要维护的心态。
我找到了很多关于什么 的信息STATISTICS:如何维护它们,如何从查询或索引手动或自动创建它们,等等。但是,我一直无法找到有关何时的任何指导或“最佳实践”信息创建它们:在哪些情况下,手动创建的 STATISTICS 对象比索引更受益。我已经看到手动创建的过滤统计有助于对分区表的查询(因为为索引创建的统计覆盖了整个表而不是每个分区——brillaint!),但肯定有其他场景可以从统计对象中受益,同时不需要索引的详细信息,也不值得维护索引或增加阻塞/死锁机会的成本。
@JonathanFite 在评论中提到了索引和统计数据之间的区别:
索引将通过创建排序与表本身不同的查找来帮助 SQL 更快地找到数据。统计信息帮助 SQL 确定满足查询需要多少内存/工作量。
这是很好的信息,主要是因为它帮助我澄清了我的问题:
如何知道这(或在任何其他技术信息什么S和如何S的相关的行为和性质STATISTICS)帮助确定何时选择CREATE STATISTICS在CREATE INDEX创建索引将创建相关的时候,尤其是STATISTICS对象?什么情况下只有统计信息而没有索引会更好地服务?
如果可能的话,有一个场景的工作示例,其中STATISTICS对象比INDEX.
由于我是一名视觉学习者/思考者,我认为将esSTATISTICS和INDEXes之间的差异并排查看可能有助于确定何时STATISTICS是更好的选择。
Thingy PROs CONs
------- ---------- -------------------
INDEX * Can help sorts. * Takes up space.
* Contains data (can * Needs to be maintained (extra I/O).
"cover" a …Run Code Online (Sandbox Code Playgroud) 我有一个我无法理解的情况。我的 SQL Server 执行计划告诉我,我缺少表上的统计信息,但统计信息已经创建:

但是如果我们查看表格,我们会看到有一个自动创建的统计信息:

有人可以帮助理解它是怎么回事吗?
Auto_Update 和 Auto_Create 统计信息在当前数据库上打开。
我正在使用 SQL Server 2014。
查询优化器使用的统计信息物理存储在 SQL Server 数据库文件和缓冲池中的什么位置?
更具体地说,有没有办法使用 DMV 和/或 DBCC 找出统计数据使用的页面?
我拥有 SQL Server 2008 Internals 和 SQL Server Internals and Troubleshooting 书籍,但没有一本涉及统计的物理结构;如果他们这样做,我将无法找到此信息。
假设我有一个Foo包含列ID1, ID2和一个复合主键的表ID2, ID1。(我目前正在使用 System Center 产品,该产品具有以这种方式定义的多个表,主键列以它们在表定义中出现的相反顺序列出。)
CREATE TABLE dbo.Foo(
ID1 int NOT NULL,
ID2 int NOT NULL,
CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED (ID2, ID1)
);
GO
-- Add a row and update stats so that histogram isn't empty
INSERT INTO Foo (ID1, ID2) VALUES (1,2);
UPDATE STATISTICS dbo.Foo;
Run Code Online (Sandbox Code Playgroud)
的key_ordinal列sys.index_columns示出了它们在复合材料中的主键被宣布相同顺序的索引列:
SELECT t.name, i.name, c.column_id, c.name, ic.index_column_id, ic.key_ordinal
FROM sys.tables AS t
JOIN sys.indexes AS i
ON t.[object_id] = i.[object_id]
JOIN sys.index_columns …Run Code Online (Sandbox Code Playgroud) 我一直在研究 SQL Server (2012) 上的统计更新的采样阈值,并注意到一些奇怪的行为。基本上,采样的行数在某些情况下似乎有所不同 - 即使是相同的数据集。
我运行这个查询:
--Drop table if exists
IF (OBJECT_ID('dbo.Test')) IS NOT NULL DROP TABLE dbo.Test;
--Create Table for Testing
CREATE TABLE dbo.Test(Id INT IDENTITY(1,1) CONSTRAINT PK_Test PRIMARY KEY CLUSTERED, TextValue VARCHAR(20) NULL);
--Insert enough data so we have more than 8Mb (the threshold at which sampling kicks in)
INSERT INTO dbo.Test(TextValue)
SELECT TOP 1000000 'blahblahblah'
FROM sys.objects a, sys.objects b, sys.objects c, sys.objects d;
--Create Index on TextValue
CREATE INDEX IX_Test_TextValue ON dbo.Test(TextValue);
--Update Statistics …Run Code Online (Sandbox Code Playgroud) 我的印象是,当LIKE在所有针对未知场景的优化中使用运算符时,旧版和新版 CE 都使用 9% 的估计值(假设相关统计数据可用并且查询优化器不必求助于选择性猜测)。
当对信用数据库执行以下查询时,我在不同的 CE 下得到不同的估计。在新的 CE 下,我收到了我期望的 900 行的估计值,在旧版 CE 下,我收到了 241.416 的估计值,但我无法弄清楚这个估计值是如何得出的。有没有人能够发光?
-- New CE (Estimate = 900)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName;
-- Forcing Legacy CE (Estimate = 241.416)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName
OPTION (
QUERYTRACEON 9481,
QUERYTRACEON 9292,
QUERYTRACEON 9204,
QUERYTRACEON 3604
);
Run Code Online (Sandbox Code Playgroud)
在我的场景中,我已经将信用数据库设置为兼容性级别 120,因此为什么在第二个查询中我使用跟踪标志来强制使用旧版 CE 并提供有关查询优化器使用/考虑的统计信息的信息。我可以看到正在使用有关“姓氏”的列统计信息,但我仍然无法弄清楚 241.416 的估计值是如何得出的。
除了这篇 Itzik Ben-Gan 文章之外,我在网上找不到任何其他 …
sql-server optimization statistics sql-server-2014 cardinality-estimates
除了使用 SQL Server Profiler 之外,还有什么方法可以跟踪正在使用的存储过程,或者至少是上次执行它们的时间?
我们有一个使用增量统计的大型分区 SQL Server 数据库。所有索引都是分区对齐的。当我们尝试逐个分区联机重建一个分区时,所有统计信息在重建索引后都会消失。
下面是使用 AdventureWorks2014 数据库在 SQL Server 2014 中复制问题的脚本。
--Example against AdventureWorks2014 Database
CREATE PARTITION FUNCTION TransactionRangePF1 (DATETIME)
AS RANGE RIGHT FOR VALUES
(
'20130501', '20130601', '20130701', '20130801',
'20130901', '20131001', '20131101', '20131201',
'20140101', '20140201', '20140301'
);
GO
CREATE PARTITION SCHEME TransactionsPS1 AS PARTITION TransactionRangePF1 TO
(
[PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY],
[PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY], [PRIMARY],
[PRIMARY], [PRIMARY], [PRIMARY]
);
GO
CREATE TABLE dbo.TransactionHistory
(
TransactionID INT NOT NULL, -- not bothering with IDENTITY here
ProductID INT NOT …Run Code Online (Sandbox Code Playgroud) sql-server ×10
statistics ×10
index ×1
index-tuning ×1
maintenance ×1
optimization ×1
partitioning ×1
performance ×1