Sqlserver
 sql >> Teknologi Basis Data >  >> RDS >> Sqlserver

Kebuntuan saat menanyakan INFORMATION_SCHEMA

  1. Tampilan INFORMATION_SCHEMA hanya itu - tampilan. Anda tidak dapat memperbaruinya sehingga tidak mungkin menyebabkan kebuntuan. Jika Anda ingin menentukan sumber sebenarnya (yang saya asumsikan ada hubungannya dengan perubahan Anda, atau kode lain di dalam kursor yang tidak Anda tunjukkan, atau kode lain yang Anda panggil dalam kombinasi dengan memanggil prosedur ini - karena memilih melawan dilihat dan kemudian memilih variabel tidak dapat menjadi penyebabnya), saya sarankan membaca Pos blog Gail Shaw tentang menafsirkan kebuntuan .

  2. Terlepas dari (1) saya masih menyarankan untuk menggunakan tampilan katalog yang lebih modern daripada INFORMATION_SCHEMA. Informasi yang sama dapat diperoleh dari, misalnya, sys.key_constraints.

  3. Anda menggunakan opsi kursor default; dan Anda membuat kursor bersarang. Jika pada akhirnya Anda masih menggunakan kursor, Anda harus membiasakan diri menggunakan kursor dengan sumber daya yang lebih sedikit (mis. LOCAL STATIC FORWARD_ONLY READ_ONLY).

  4. Anda sebenarnya tidak memerlukan kursor untuk melakukan ini. Inilah cara saya menulis ulang skrip tabel PK:

    CREATE PROCEDURE dbo.ScriptPKForTable
        @TableName SYSNAME
    AS
    BEGIN
        SET NOCOUNT ON;
    
        DECLARE 
          @pkName    SYSNAME,
          @clustered BIT,
          @object_id INT,
          @sql       NVARCHAR(MAX);
    
        SELECT
          @object_id = OBJECT_ID(UPPER(@TableName));
    
        SELECT
          @pkName = kc.name,
          @clustered = CASE i.[type] 
            WHEN 1 THEN 1 ELSE 0 END
        FROM 
            sys.key_constraints AS kc
        INNER JOIN 
            sys.indexes AS i
            ON kc.parent_object_id = i.[object_id]
            AND kc.unique_index_id = i.index_id
        WHERE
            kc.parent_object_id = @object_id
            AND kc.[type] = 'pk';
    
        SET @sql = N'ALTER TABLE ' + QUOTENAME(@TableName)
          + ' ADD CONSTRAINT ' + @pkName 
          + ' PRIMARY KEY ' + CASE @clustered 
          WHEN 1 THEN 'CLUSTERED' ELSE '' END + ' (';
    
        SELECT
          @sql = @sql + c.name + ','
        FROM 
          sys.index_columns AS ic
        INNER JOIN
          sys.indexes AS i 
          ON ic.index_id = i.index_id
          AND ic.[object_id] = i.[object_id]
        INNER JOIN 
          sys.key_constraints AS kc
          ON i.[object_id] = kc.[parent_object_id]
          AND kc.unique_index_id = i.index_id
        INNER JOIN 
          sys.columns AS c
          ON i.[object_id] = c.[object_id]
          AND ic.column_id = c.column_id
        WHERE
          kc.[type] = 'PK'
          AND kc.parent_object_id = @object_id
        ORDER BY key_ordinal;
    
        SET @sql = LEFT(@sql, LEN(@sql) - 1) + ');';
    
        SELECT COALESCE(@sql, ' ');
    END
    GO
    

Adapun skrip pembuatan indeks, saya pikir ada cara yang lebih baik untuk melakukan ini (sekali lagi tanpa kursor eksplisit, bukan berarti menghindari kursor adalah tujuannya, tetapi kodenya akan menjadi BANYAK lebih bersih). Pertama, Anda memerlukan fungsi untuk membuat kunci atau menyertakan kolom dari indeks:

CREATE FUNCTION dbo.BuildIndexColumns
(
    @object_id        INT,
    @index_id         INT,
    @included_columns BIT
)
RETURNS NVARCHAR(MAX)
AS
BEGIN
  DECLARE @s NVARCHAR(MAX);

  SELECT @s = N'';

  SELECT @s = @s + c.name + CASE ic.is_descending_key
    WHEN 1 THEN ' DESC' ELSE '' END + ',' 
    FROM sys.index_columns AS ic
    INNER JOIN sys.columns AS c
    ON ic.[object_id] = c.[object_id]
    AND ic.column_id = c.column_id
    WHERE c.[object_id] = @object_id
    AND ic.[object_id] = @object_id
    AND ic.index_id = @index_id
    AND ic.is_included_column = @included_columns
    ORDER BY ic.key_ordinal;

  IF @s > N''
    SET @s = LEFT(@s, LEN(@s)-1);

  RETURN (NULLIF(@s, N''));
END
GO

Dengan fungsi tersebut, prosedur ScriptIndexes cukup mudah:

CREATE PROCEDURE dbo.ScriptIndexesForTable
    @TableName SYSNAME
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE
      @sql       NVARCHAR(MAX),
      @object_id INT;

  SELECT @sql = N'', @object_id = OBJECT_ID(UPPER(@TableName));

  SELECT @sql = @sql + 'CREATE '
      + CASE i.is_unique WHEN 1 THEN 'UNIQUE ' ELSE '' END
      + CASE i.[type] WHEN 1 THEN 'CLUSTERED ' ELSE '' END
      + ' INDEX ' + i.name + ' ON ' + QUOTENAME(@TableName) + ' (' 
      + dbo.BuildIndexColumns(@object_id, i.index_id, 0)
      + ')' + COALESCE(' INCLUDE(' 
      + dbo.BuildIndexColumns(@object_id, i.index_id, 1)
      + ')', '') + ';' + CHAR(13) + CHAR(10)
  FROM
      sys.indexes AS i
  WHERE
      i.[object_id] = @object_id
      -- since this will be covered by ScriptPKForTable:
      AND i.is_primary_key = 0
  ORDER BY i.index_id;

  SELECT COALESCE(@sql, ' ');
END
GO

Perhatikan bahwa solusi saya tidak menganggap PK dikelompokkan (skrip PK Anda hard-code CLUSTERED tetapi kemudian skrip indeks Anda mengasumsikan bahwa salah satu indeks dapat dikelompokkan). Saya juga mengabaikan properti tambahan seperti filegroup, partisi, atau indeks yang difilter (tidak didukung pada tahun 2005).




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Server:Panjang karakter maksimum dari nama objek

  2. Clustered vs Non-Clustered

  3. Cadangkan Database di SQL Server 2017

  4. Kesalahan pemulihan basis data SQL Server:pemeran yang ditentukan tidak valid. (SqlManagerUI)

  5. Cara Mengganti NULL dengan Nilai Lain di SQL Server – ISNULL()