在SQL表上创建统计信息之前,请检查具有相同列的统计信息是否存在

时间:2018-07-28 19:57:01

标签: sql sql-server

我需要在具有不同列组合的表上创建一些统计信息。但是,对于相同的列组合,可能已经存在一些统计信息。因此,在创建具有列组合的统计信息之前,我想检查是否存在具有相同列组合的统计信息。如果存在,那么我将不创建统计信息;如果不存在,则仅我将创建统计信息。

例如,如下创建一个表和该表的统计信息:

CREATE TABLE Gift
(
     Gift_Id INTEGER IDENTITY (1,1) PRIMARY KEY,
     Person_Id INTEGER,
     Event_Id INTEGER,
     Agent_Id INTEGER,
     Fund_Id INTEGER,
     Amount FLOAT
)

CREATE STATISTICS [Stats1_1_2_3] 
    ON [dbo].[Gift]([Gift_Id], [Person_Id], [Event_Id])

因此,我们有一个表Gift和一个统计信息,其中包含Gift_ID,Person_Id和Event_Id列。

现在,如果我创建另一个统计数据如下:

CREATE STATISTICS [Stats2_1_2_3] 
    ON [dbo].[Gift]([Gift_Id], [Person_Id], [Event_Id])

请参阅稍后的统计信息与第一个统计信息重复(具有相同的列)。

因此,为避免重复,我需要检查是否存在具有相同列的统计信息。

有什么办法吗?

请帮助

2 个答案:

答案 0 :(得分:2)

以下查询将检查sys.stats,sys.stats_columns和sys.columns表,以查找给定表的所有统计信息,并获取每个统计信息的每一列。 分组和计数是为了检查是否存在引用所有列的统计信息。
请注意,查询中明确提到了表名,列名和要检查的列数。 更新后的查询还将检查是否仅存在列出的列(计数= 3)和列出的所有列(计数3 = 3)。用于其他统计信息将涉及CASE语句的修改以及WHERE最后一行中的“ 3”值。

SELECT * FROM (
  SELECT s.name AS statistics_name,
      count(*) as counting,
      sum(case
          when c.name = 'Gift_Id' then 1
          when c.name = 'Person_Id' then 1
          when c.name = 'Event_Id' then 1
          else 0
      end) as counting3
  FROM sys.stats AS s  
  INNER JOIN sys.stats_columns AS sc   
  ON s.object_id = sc.object_id AND s.stats_id = sc.stats_id  
  INNER JOIN sys.columns AS c   
  ON sc.object_id = c.object_id AND c.column_id = sc.column_id  
  WHERE s.object_id = OBJECT_ID('Gift')
  Group by s.name) T
WHERE T.COUNTING = 3 AND T.COUNTING3 = 3;

lzutf8

答案 1 :(得分:1)

以下查询将使用给定的列组合给出统计信息的名称(如果存在)。

SELECT s.name
FROM sys.stats s inner join
sys.stats_columns sc on s.stats_id = sc.stats_id and s.object_id = sc.object_id
JOIN sys.columns c ON c.[object_id] = sc.[object_id] AND c.column_id = sc.column_id
WHERE OBJECT_NAME(s.OBJECT_ID) = 'Gift'
and s.stats_id not in 
(
    SELECT distinct s.stats_id 
    FROM sys.stats s inner join
    sys.stats_columns sc on s.stats_id = sc.stats_id and s.object_id = sc.object_id
    JOIN sys.columns c ON c.[object_id] = sc.[object_id] AND c.column_id = sc.column_id
    WHERE OBJECT_NAME(s.OBJECT_ID) = 'Gift' and c.name not in ('Gift_Id','Person_Id','Event_Id')
)
group by s.name
having count(1)= 3

Updated SQLFiddle for the above