Joh*_*ohn 10 sql-server statistics
SQL Server 有一种叫做“多列统计”的东西,但这并不是人们认为的意思。
我们来看看下面的示例表:
CREATE TABLE BadStatistics
(
IsArchived BIT NOT NULL,
Id INT NOT NULL IDENTITY PRIMARY KEY,
Mystery VARCHAR(200) NOT NULL
);
CREATE NONCLUSTERED INDEX BadIndex
ON BadStatistics (IsArchived, Mystery);
Run Code Online (Sandbox Code Playgroud)
这样,我们就在我们拥有的两个索引上创建了两个统计信息:
BadIndex 的统计数据:
+--------------+----------------+-------------------------+
| All density | Average Length | Columns |
+--------------+----------------+-------------------------+
| 0.5 | 1 | IsArchived |
+--------------+----------------+-------------------------+
| 4.149378E-06 | 37 | IsArchived, Mystery |
+--------------+----------------+-------------------------+
| 4.149378E-06 | 41 | IsArchived, Mystery, Id |
+--------------+----------------+-------------------------+
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 0 | 0 | 24398 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 216602 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Run Code Online (Sandbox Code Playgroud)
聚集索引的统计信息:
+--------------+----------------+---------+
| All density | Average Length | Columns |
+--------------+----------------+---------+
| 4.149378E-06 | 4 | Id |
+--------------+----------------+---------+
+--------------+------------+---------+---------------------+----------------+
| RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+--------------+------------+---------+---------------------+----------------+
| 1 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
| 240999 | 240997 | 1 | 240997 | 1 |
+--------------+------------+---------+---------------------+----------------+
| 241000 | 0 | 1 | 0 | 1 |
+--------------+------------+---------+---------------------+----------------+
Run Code Online (Sandbox Code Playgroud)
(我用随机样本数据填充了表格,其中大约十分之一的行是非存档的。之后我运行了完整的扫描统计更新。)
为什么两列统计的直方图只使用一列?我知道很多人都写过它确实如此,但是原理是什么?在这种情况下,它会使整个直方图变得不那么有用,因为第一列只有两个值。为什么要这样随意限制统计数据?
请注意,这个问题不是指多维直方图,这是一种完全不同的野兽。它是关于一维直方图,其中一维是包含相应多列的元组。
当前的 SQL Server 模型仅使用单列直方图和多列密度信息。单列直方图用于估计合适谓词的选择性,例如a = 1或b > 50。具有多个谓词的查询简单地组合了各个选择性(带有假设)以产生估计的整体选择性。
例如,请参阅我的文章Cardinality Estimation: Combining Density Statistics
多列密度通过为多个相等谓词和聚合的分组基数提供弱相关信息来进一步通知模型。
与索引相关的统计信息是该模型的一个机会性附加组件:引擎在构建索引时也可以收集(通常是完整扫描)统计信息。SQL Server 自动为其他键构造前导列直方图和密度信息。
对于在索引非引导列的柱状图可以按需自动查询处理器预先使用构造的,或者sp_createstats与所述@indexonly选项(等等)。
组合单列统计数据(如上所述)时所做的假设可能会也可能不会很好地模拟数据的现实情况。在许多情况下,可用的选项(指数退避、独立性、最小选择性)会产生“足够好”的估计。
我们还过滤了统计信息(和索引)作为低基数前导列索引的自然解决方案,例如在问题示例中。将这些推向逻辑的极端会使我们更接近问题所不涉及的多维统计数据。
当可用的建模选项无法提供合适的估计时,在某些情况下,多列统计直方图确实可以为合适的索引谓词提供更好的选择性估计。在不同的列中组合不同的数据类型有一些困难,但没有什么不可克服的。
我们还需要每个索引键级别的直方图(为了获得最佳结果);所以对于一个索引(a, b, c),这将意味着在直方图(a, b)和(a, b, c)除对当前单列直方图(a)孤单。
用于检测陈旧统计数据的机制也需要修改以维护受影响的多列直方图。这些直方图最终可能会比单列统计数据更频繁地重建,因为对更多列的修改会影响它们。
所有这些都会增加规模、复杂性和维护开销。
可以使用在引用多列的精心构造的计算列上创建的统计数据来模拟(在有限范围内)多列统计数据。查询需要在计算列上包含一个谓词(或基础公式的精确文本匹配)以利用该统计信息。这种方法可行的情况可能只有非常有限的情况。然而,它与自动多列直方图存在一些相同的实现问题。
最终,唯一可以确定为什么 SQL Server 不支持多列统计信息的人将是设计者自己。如果您觉得您可以为该领域的产品改进提出一个具有广泛适用性的有力案例,您可以在Connect 上或通过您的正常支持渠道提出建议。
在这种情况下,它会使整个直方图变得不那么有用,因为第一列只有两个值
直方图还提供了有关值的前导列分布的有用信息:当统计建成,共有24,398行,其中IsArchived是假的,和216602行哪里是真。
此外,statistics 对象告诉我们有 (1 / 0.5) = 2 个不同的值 for IsArchived, (1 / 4.149378E-06) ~= 241000 个不同的值 for(IsArchived, Mystery)平均行大小为 37 字节,并且(IsArchived, Mystery, Id)与每行 4 个额外字节。
这些都是很好的通用信息,可以与有关其他列的统计信息结合使用,以在具有多个谓词的查询中生成选择性估计(如上所述)。
| 归档时间: |
|
| 查看次数: |
1333 次 |
| 最近记录: |