Sql server SQL统计信息和索引-详细程度如何?

Sql server SQL统计信息和索引-详细程度如何?,sql-server,statistics,performance,Sql Server,Statistics,Performance,统计数据(有助于决定是否使用索引)是否考虑到每列值的行数,还是只使用每列值的行数 假设我有一个表,有一个名为active的位列,它有一百万行,但99.99%设置为false。如果我在这个列上有一个索引,那么Sql是否足够聪明,知道在搜索active=1时使用索引,但在搜索active=0时没有意义 另一个例子,如果我有一个表,它有1000000条记录,其中一个索引列包含大约50000个不同的值,每个值的平均行数为10,但是一个特殊值有500000行。如果搜索此特殊记录,索引可能不会有用,但在查找

统计数据(有助于决定是否使用索引)是否考虑到每列值的行数,还是只使用每列值的行数

假设我有一个表,有一个名为active的位列,它有一百万行,但99.99%设置为false。如果我在这个列上有一个索引,那么Sql是否足够聪明,知道在搜索active=1时使用索引,但在搜索active=0时没有意义

另一个例子,如果我有一个表,它有1000000条记录,其中一个索引列包含大约50000个不同的值,每个值的平均行数为10,但是一个特殊值有500000行。如果搜索此特殊记录,索引可能不会有用,但在查找任何其他代码时,索引将非常有用


但这种特殊情况会破坏指数的有效性吗

它创建了一个Historogram,因此将使用它

通过一个bit列,可以很好地了解0和1的数量

通过一个字符串列,我将大致了解“bands”(从a、b、c等开始的值)。数字也是如此(它创建了x个值范围的条带)


只需在您的管理工作室中查看统计数据,您就可以实际访问直方图。

您可以自己查看:

CREATE TABLE IndexTest (
Id int not null primary key identity(1,1),
Active bit not null default(0),
IndexedValue nvarchar(10) not null
)

CREATE INDEX IndexTestActive ON IndexTest (Active)
CREATE INDEX IndexTestIndexedValue ON IndexTest (IndexedValue)

DECLARE @values table
(
    Id int primary key IDENTITY(1, 1),
    Value nvarchar(10)
)

INSERT INTO @values(Value) VALUES ('1')
INSERT INTO @values(Value) VALUES ('2')
INSERT INTO @values(Value) VALUES ('3')
INSERT INTO @values(Value) VALUES ('4')
INSERT INTO @values(Value) VALUES ('5')
INSERT INTO @values(Value) VALUES ('Many')
INSERT INTO @values(Value) VALUES ('Many')
INSERT INTO @values(Value) VALUES ('Many')
INSERT INTO @values(Value) VALUES ('Many')
INSERT INTO @values(Value) VALUES ('Many')

DECLARE @rowCount int
SET @rowCount = 100000

WHILE(@rowCount > 0)
BEGIN
    DECLARE @valueIndex int
    SET @valueIndex = CAST(RAND() * 10 + 1 as int)
    DECLARE @selectedValue nvarchar(10)
    SELECT @selectedValue = Value FROM @values WHERE Id = @valueIndex
    DECLARE @isActive bit
    SELECT @isActive = CASE 
            WHEN RAND() < 0.001 THEN 1 
            ELSE 0
           END
    INSERT INTO IndexTest(Active, IndexedValue) VALUES (@isActive, @selectedValue)
    SET @rowCount = @rowCount - 1
END

SELECT count(*) FROM IndexTest WHERE Active = 1
SELECT count(*) FROM IndexTest WHERE Active = 0

SELECT count(*) FROM IndexTest WHERE IndexedValue = '1'
SELECT count(*) FROM IndexTest WHERE IndexedValue = 'Many'
CREATE TABLE IndexTest(
Id int非空主键标识(1,1),
活动位不为空默认值(0),
IndexedValue nvarchar(10)不为空
)
在IndexTest上创建索引IndexTestive(活动)
在IndexTest(IndexedValue)上创建索引IndexTestIndexedValue
声明@values表
(
Id int主键标识(1,1),
值nvarchar(10)
)
插入@values(Value)values('1')中
插入@values(Value)values('2')中
插入@values(Value)values('3')中
插入@values(Value)values('4')中
插入@values(Value)values('5')中
插入@values(Value)values('Many')中
插入@values(Value)values('Many')中
插入@values(Value)values('Many')中
插入@values(Value)values('Many')中
插入@values(Value)values('Many')中
声明@rowcountint
设置@rowCount=100000
而(@rowCount>0)
开始
声明@valueIndex int
设置@valueIndex=CAST(RAND()*10+1为int)
声明@selectedValue nvarchar(10)
从@values中选择@selectedValue=Value,其中Id=@valueIndex
声明@isActive位
选择@isActive=CASE
当RAND()小于0.001时,则为1
其他0
结束
插入IndexTest(活动,IndexedValue)值(@isActive,@selectedValue)
设置@rowCount=@rowCount-1
结束
从IndexTest中选择count(*),其中Active=1
从IndexTest中选择count(*),其中Active=0
从IndexTest中选择count(*),其中IndexedValue='1'
从IndexTest中选择count(*),其中IndexedValue='Many'
在我看来,它总是使用此查询计划上的索引:


您只需查看统计数据并亲自查看:)。请参阅备注部分,它很好地解释了直方图的实际存储和使用方式:

要创建直方图,查询 优化器对列值进行排序, 计算包含的值的数目 匹配每个不同的列值并 然后将列值聚合为 最多200个连续直方图 步骤。每个步骤包括一系列 列值后跟一个上限 绑定列值。范围包括 之间所有可能的列值 边界值,不包括 边界值本身。最低的 已排序列值的 第一类的上边界值 直方图步长

对于每个直方图步骤:

  • 粗体线表示上边界值(范围\高\键)和 发生的次数(相等行)
  • RANGE_HI_键左侧的实心区域表示列值的范围 以及平均每次的次数 出现列值(平均范围行)。 第一行的平均范围 直方图步长始终为0
  • 虚线表示用于估计总计的采样值 范围中不同值的数目 (不同的行数)和总数 范围内的值的数量(范围\行)。 查询优化器使用范围\行 和不同的要计算的行 AVG_RANGE_行,不存储 采样值
查询优化器定义 直方图步骤根据其 统计显著性。它使用一个 最大差分算法 最小化过程中的步骤数 直方图,同时最大化 边界之间的差异 价值观最大步骤数为 200直方图步数可以小于不同的步数 值,即使是包含较少值的列 超过200个边界点。例如 可以使用具有100个不同值的列 具有小于100的直方图 边界点


谢谢这很有帮助。如果我使用where Active=0和IndexedValue='1',它将执行表扫描,而Active=1和IndexValue='1'将使用索引。这不是一个很好的测试。您应该使用
SELECT*
,因为它当然会始终使用
COUNT(*)的索引