2009-07-13 5 views
2

照合変更練習の一環として、削除してから再作成する必要があるインデックスのリスト(122)があります。 GUIを通過してそのたびにクエリウィンドウにスクリプトを記述することなく、これらのインデックスを再作成するにはどうすればよいですか?インデックスのインデックスリスト用のCREATEスクリプトを生成

私のリストはジュニアDBAはとても私と我慢してください。このスクリプト

WITH indexCTE AS 
    ( 
    SELECT Table_Name, Column_Name, Collation_Name 
    FROM information_schema.columns 
    WHERE Collation_Name IS NOT NULL AND Collation_Name = 'Modern_Spanish_CI_AS' 
    ), 
    indexCTE2 AS 
    (
    SELECT i.Name [Index Name], OBJECT_NAME(i.object_ID) [Table Name], c.Name [Column Name] 
    FROM sys.indexes i 
    INNER JOIN sys.index_columns ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id 
    INNER JOIN sys.columns c ON ic.column_id = c.column_id AND ic.object_id = c.OBJECT_ID 
    WHERE EXISTS (SELECT 1 FROM indexCTE t1 WHERE t1.Table_Name = OBJECT_NAME(i.object_ID) AND t1.Column_Name = c.Name) 
    ) SELECT * FROM indexCTE2 

あなたはおそらく言うことができるように、私はまだだから取得されます!

ありがとうございます!

答えて

9

あなたはかなり近いです、私はこれを試しましたが、これがあなたのために働くかどうかを確認して、予想される122の指標を再現することを示しますか?

UPDATE:CLUSTEREDとNONCLUSTEREDのインデックスタイプを判別し、INCLUDEd列をインデックス定義に追加する機能が追加されました。

WITH indexCTE AS 
(
    SELECT DISTINCT 
     i.index_id, i.name, i.object_id 
    FROM 
     sys.indexes i 
    INNER JOIN 
     sys.index_columns ic 
      ON i.index_id = ic.index_id AND i.object_id = ic.object_id 
    WHERE 
     EXISTS (SELECT * FROM sys.columns c 
       WHERE c.collation_name = 'Modern_Spanish_CI_AS' 
       AND c.column_id = ic.column_id AND c.object_id = ic.object_id) 
), 
indexCTE2 AS 
(
    SELECT 
     indexCTE.name 'IndexName', 
     OBJECT_NAME(indexCTE.object_ID) 'TableName', 
     CASE indexCTE.index_id 
      WHEN 1 THEN 'CLUSTERED' 
      ELSE 'NONCLUSTERED' 
     END AS 'IndexType', 
     (SELECT DISTINCT c.name + ',' 
     FROM 
      sys.columns c 
     INNER JOIN 
      sys.index_columns ic 
       ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 0 
     WHERE 
      indexCTE.OBJECT_ID = ic.object_id 
      AND indexCTE.index_id = ic.index_id 
     FOR XML PATH('') 
     ) ixcols, 
     ISNULL(
     (SELECT DISTINCT c.name + ',' 
     FROM 
      sys.columns c 
     INNER JOIN 
      sys.index_columns ic 
       ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 1 
     WHERE 
      indexCTE.OBJECT_ID = ic.object_id 
      AND indexCTE.index_id = ic.index_id 
     FOR XML PATH('') 
     ), '') includedcols 
    FROM 
     indexCTE 
) 
SELECT 
    'CREATE ' + IndexType + ' INDEX ' + IndexName + ' ON ' + TableName + 
     '(' + SUBSTRING(ixcols, 1, LEN(ixcols)-1) + 
     CASE LEN(includedcols) 
      WHEN 0 THEN ')' 
      ELSE ') INCLUDE (' + SUBSTRING(includedcols, 1, LEN(includedcols)-1) + ')' 
     END 
FROM 
    indexCTE2 
ORDER BY 
    TableName, IndexName 

あなたが探している文CREATE INDEXはありますか?

マルク・

+0

これに伴う問題を追加複合インデックスであるインデックスをいくつか持っているということです。それらの中には列も含まれているものもあれば、ユニークなものもあります。そのように再作成することはできません。私は各インデックスの元のスキーマを複製する必要があります... – super9

+0

何が問題なのですか?このスクリプトでは、インデックスの列数はどれくらいであっても* ALL *でなければなりません。 –

+0

はいカラム名がありますが、属性はありません。たとえば、インデックスが非クラスタ化され、列が含まれている場合、CREATE NONCLUSTERED INDEX ON ()INCLUDE などなどが必要です。付属の列などは取得できません。 – super9

1
DECLARE @T_IndexInfo TABLE 
    (
     IndID NVARCHAR(128), 
     ObjectID NVARCHAR(128), 
     ColID NVARCHAR(128), 
     IndexName NVARCHAR(128), 
     TableName NVARCHAR(128), 
     ColumnName NVARCHAR(128), 
     KeyNo NVARCHAR(128), 
     ColType NVARCHAR(128) 
    ) 

INSERT INTO @T_IndexInfo 
     SELECT I.IndID, 
       SO.ID AS 'ObjectID', 
       SK.ColID, 
       I.Name AS 'IndexName', 
       SO.Name AS 'TableName', 
       SC.Name AS 'ColumnName', 
       Sk.KeyNo, 
       CASE WHEN Sk.KeyNo = 0 THEN 'Include' 
        ELSE 'Normal' 
       END AS 'ColType' 
     FROM sys.sysindexes I 
       INNER JOIN sys.sysobjects SO ON SO.ID = I.ID 
               AND SO.xtype = 'U' 
       INNER JOIN sys.sysindexkeys SK ON SK.IndID = I.IndID 
                AND SO.ID = SK.ID 
       INNER JOIN sys.syscolumns SC ON SC.ID = SO.ID 
               AND SC.ColID = SK.ColID 
     WHERE I.IndID > 0 
       AND I.IndID < 255 
       AND (I.Status & 64) = 0 
--    AND (I.status & 2048) <> 2048 /******** comment this if PK's also need to be recreated *****/ 
     ORDER BY SO.Name, 
       I.Name 

DECLARE @T_Final TABLE 
    (
     TableName NVARCHAR(128), 
     IndexName NVARCHAR(128), 
     NormalColumns NVARCHAR(MAX), 
     IncludedColumns NVARCHAR(MAX) 
    ) 

INSERT INTO @T_Final 
     SELECT DISTINCT 
       TableName, 
       IndexName, 
       STUFF((SELECT ',[' + ColumnName + ']' 
         FROM @T_IndexInfo 
         WHERE IndID = I.IndID 
           AND ObjectID = I.ObjectID 
           AND ColType = 'Normal' 
         ORDER BY KeyNo 
         FOR 
         XML PATH('') 
        ), 1, 1, '') AS 'NormalColumns', 
       STUFF((SELECT ',[' + ColumnName + ']' 
         FROM @T_IndexInfo 
         WHERE IndID = I.IndID 
           AND ObjectID = I.ObjectID 
           AND ColType = 'Include' 
         FOR 
         XML PATH('') 
        ), 1, 1, '') AS 'IncludedColumns' 
     FROM @T_IndexInfo I; 

WITH indexCTE AS 
    ( 
    SELECT Table_Name, Column_Name --, Collation_Name 
    FROM information_schema.columns 
    WHERE Collation_Name IS NOT NULL AND Collation_Name = 'Modern_Spanish_CI_AS' 
    ), 
    indexCTE2 AS 
    (
    SELECT i.Name [Index Name], OBJECT_NAME(i.object_ID) [Table Name], c.Name [Column Name] 
    FROM sys.indexes i 
    INNER JOIN sys.index_columns ic ON i.index_id = ic.index_id AND i.object_id = ic.object_id 
    INNER JOIN sys.columns c ON ic.column_id = c.column_id AND ic.object_id = c.OBJECT_ID 
    WHERE EXISTS (SELECT 1 FROM indexCTE t1 WHERE t1.Table_Name = OBJECT_NAME(i.object_ID) AND t1.Column_Name = c.Name) 
    ) 

SELECT IndexName, TableName, NormalColumns, IncludedColumns 
INTO #temp1 
FROM @T_Final z INNER JOIN indexCTE2 x ON z.IndexName = x.[Index Name] 

-- To generate CREATE INDEX SCRIPT 
SELECT 'CREATE INDEX [' + IndexName + '] ON [' + TableName + '].(' 
     + NormalColumns + ')' + CASE WHEN IncludedColumns IS NULL THEN '' 
            ELSE ' INCLUDE (' + IncludedColumns + ')' 
           END AS 'CreateScript' 
FROM #temp1 

-- To generate DROP INDEX SCRIPT 
SELECT 'DROP INDEX [' + TableName + '].[' + IndexName + ']' AS 'DropScript' 
FROM #temp1 

のDROP TABLEの#1 TEMP1

0

これは少しオフトピックですが、私はとにかくこれを示唆するだろうと思った:

を、あなたのスクリプトの実行を維持したくない場合SQL Server管理スタジオでは、次のようなファイルを含むrunmyscripts.batファイルを作成することができます。

@echo off 

echo Execute Scripts... 

sqlcmd -i C:\Scripts\myscript1.sql 
sqlcmd -i C:\Scripts\myscript2.sql 

echo Scripts Complete. 
echo Press any button to exit. 
pause 
4

偉大なスクリプトMarc。 私が欠けていると思うのは、各列の昇順または降順のインジケータだけです。 sys.index_columnsビューのis_descending_key列に応じてASCまたはDESCに追加するインデックス付き列のcase文を含めるようにスクリプトを修正しました。

WITH indexCTE AS 
(
    SELECT DISTINCT 
     i.index_id, i.name, i.object_id 
    FROM 
     sys.indexes i 
    INNER JOIN 
     sys.index_columns ic 
      ON i.index_id = ic.index_id AND i.object_id = ic.object_id 
    WHERE 
     EXISTS (SELECT * FROM sys.columns c 
       WHERE 
       c.collation_name = 'Modern_Spanish_CI_AS' 
       AND c.column_id = ic.column_id AND c.object_id = ic.object_id) 
), 
indexCTE2 AS 
(
    SELECT 
     indexCTE.name 'IndexName', 
     OBJECT_NAME(indexCTE.object_ID) 'TableName', 
     CASE indexCTE.index_id 
      WHEN 1 THEN 'CLUSTERED' 
      ELSE 'NONCLUSTERED' 
     END AS 'IndexType', 
     (SELECT CASE WHEN ic.is_descending_key = 1 THEN c.name + ' DESC ,' 
       ELSE c.name + ' ASC ,' 
       END 
     FROM 
      sys.columns c 
     INNER JOIN 
      sys.index_columns ic 
       ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 0 
     WHERE 
      indexCTE.OBJECT_ID = ic.object_id 
      AND indexCTE.index_id = ic.index_id 
     FOR XML PATH('') 
     ) ixcols, 
     ISNULL(
     (SELECT DISTINCT c.name + ',' 
     FROM 
      sys.columns c 
     INNER JOIN 
      sys.index_columns ic 
       ON c.object_id = ic.object_id AND ic.column_id = c.column_id AND ic.Is_Included_Column = 1 
     WHERE 
      indexCTE.OBJECT_ID = ic.object_id 
      AND indexCTE.index_id = ic.index_id 
     FOR XML PATH('') 
     ), '') includedcols 
    FROM 
     indexCTE 
) 
SELECT 
    'CREATE ' + IndexType + ' INDEX ' + IndexName + ' ON ' + TableName + 
     '(' + SUBSTRING(ixcols, 1, LEN(ixcols)-1) + 
     CASE LEN(includedcols) 
      WHEN 0 THEN ')' 
      ELSE ') INCLUDE (' + SUBSTRING(includedcols, 1, LEN(includedcols)-1) + ')' 
     END 
FROM 
    indexCTE2 
ORDER BY 
    TableName, IndexName 
0

TechNetには完全な解決策があります。

あなたの欲求にクエリを調整します。選択で

  • SYS.TABLESを
  • 削除デフォルト値をsys.viewsする
  • 削除/いくつかの場所の条件
関連する問題