Membuat indeks pada variabel tabel

190

Bisakah Anda membuat indeks pada variabel tabel di SQL Server 2000?

yaitu

DECLARE @TEMPTABLE TABLE (
     [ID] [int] NOT NULL PRIMARY KEY
    ,[Name] [nvarchar] (255) COLLATE DATABASE_DEFAULT NULL 
)

Bisakah saya membuat indeks Name?

GordyII
sumber
3
Ada biaya dalam membuat kedua jenis tabel temp; dan jika Anda memiliki begitu banyak data sehingga Anda perlu indeks, mungkin sudah saatnya untuk melihat menggunakan tabel nyata; bahwa Anda mengatur agar transaksi aman; filter berdasarkan id atau id pengguna dan kemudian hapus di bagian akhir. Tabel sebenarnya dan tabel temp keduanya mengalami pasang surut tetapi jika kinerja adalah masalah; coba juga dengan tabel sungguhan.
u07ch
Tabel temp 'IS' adalah tabel asli, hanya hilang saat Anda selesai. Perbedaan sebenarnya (selain itu akan hilang secara otomatis) adalah bahwa itu ada di TempDB. Ini sebenarnya besar ketika menyangkut indeks dan kendala karena Anda bisa berakhir dengan bentrokan nama, tidak hanya dengan eksekusi kode Anda yang lain, tetapi dengan eksekusi kode di database lain dalam instance Anda.
bielawski
@bielawski ini adalah variabel tabel bukan tabel temp. Variabel tabel tidak mengizinkan batasan yang disebutkan secara eksplisit, nama sistem yang dihasilkan dijamin unik. Mereka mengizinkan indeks bernama dari 2014 tetapi itu tidak masalah karena indeks hanya perlu secara unik dinamai dalam suatu objek bukan di objek.
Martin Smith
Maksud saya adalah 2 kali lipat. 1) Selain menggunakan variabel untuk menghindari keterikatan transaksi, tidak ada perbedaan material antara variabel tabel temp dan tabel. Namun dalam V-2000 tidak ada sintaks untuk menambahkan batasan, indeks ... ke variabel. 2) Diberikan seseorang dapat menggunakan tabel temp sebagai gantinya, tabel bernama appendages seperti indeks AKAN berbenturan dengan secara bersamaan mengeksekusi salinan dari SP yang sama jika nama statis digunakan! Mekanisme di bawah ini dikembangkan secara eksplisit karena saya melacak kegagalan SP ke indeks bernama bentrok selama keadaan yang tepat ini. Mereka HARUS unik.
bielawski
1
@bielawski - Tidak ada nama indeks yang tidak perlu unik di antara objek - hanya nama kendala yang melakukannya. ini sepele untuk diuji. Eksekusi sajaCREATE TABLE #T1(X INT); CREATE TABLE #T2(X INT); CREATE INDEX IX ON #T1(X); CREATE INDEX IX ON #T2(X);
Martin Smith

Jawaban:

363

Pertanyaan ini ditandai dengan SQL Server 2000 tetapi untuk kepentingan orang-orang yang mengembangkan versi terbaru saya akan membahasnya terlebih dahulu.

SQL Server 2014

Selain metode menambahkan indeks berbasis kendala yang dibahas di bawah ini, SQL Server 2014 juga memungkinkan indeks yang tidak unik ditentukan secara langsung dengan sintaks sebaris pada deklarasi variabel tabel.

Sintaks contoh untuk itu di bawah ini.

/*SQL Server 2014+ compatible inline index syntax*/
DECLARE @T TABLE (
C1 INT INDEX IX1 CLUSTERED, /*Single column indexes can be declared next to the column*/
C2 INT INDEX IX2 NONCLUSTERED,
       INDEX IX3 NONCLUSTERED(C1,C2) /*Example composite index*/
);

Indeks dan indeks yang difilter dengan kolom yang disertakan saat ini tidak dapat dideklarasikan dengan sintaks ini namun SQL Server 2016 melonggarkan ini sedikit lebih jauh. Dari CTP 3.1 sekarang dimungkinkan untuk mendeklarasikan indeks yang difilter untuk variabel tabel. Dengan RTM itu mungkin kasus yang menyertakan kolom juga diperbolehkan tetapi posisi saat ini adalah bahwa mereka "kemungkinan tidak akan masuk ke SQL16 karena keterbatasan sumber daya"

/*SQL Server 2016 allows filtered indexes*/
DECLARE @T TABLE
(
c1 INT NULL INDEX ix UNIQUE WHERE c1 IS NOT NULL /*Unique ignoring nulls*/
)

SQL Server 2000 - 2012

Bisakah saya membuat indeks pada Nama?

Jawaban singkat: Ya.

DECLARE @TEMPTABLE TABLE (
  [ID]   [INT] NOT NULL PRIMARY KEY,
  [Name] [NVARCHAR] (255) COLLATE DATABASE_DEFAULT NULL,
  UNIQUE NONCLUSTERED ([Name], [ID]) 
  ) 

Jawaban lebih rinci ada di bawah.

Tabel tradisional di SQL Server dapat memiliki indeks berkerumun atau disusun sebagai tumpukan .

Indeks yang dikelompokkan dapat dinyatakan sebagai unik untuk melarang nilai kunci duplikat atau default menjadi tidak unik. Jika tidak unik maka SQL Server menambahkan diam-diam a unikifier ke kunci duplikat untuk membuatnya unik.

Indeks non-cluster juga dapat secara eksplisit dinyatakan unik. Jika tidak, untuk kasus yang tidak unik SQL Server menambahkan baris locator (kunci indeks berkerumun atau RID untuk heap) ke semua kunci indeks (bukan hanya duplikat) ini lagi memastikan mereka unik.

Dalam SQL Server 2000 - 2012 indeks pada variabel tabel hanya dapat dibuat secara implisit dengan membuat UNIQUEatau PRIMARY KEYkendala. Perbedaan antara jenis kendala ini adalah bahwa kunci utama harus pada kolom yang tidak dapat dibatalkan. Kolom yang berpartisipasi dalam kendala unik mungkin nullable. (meskipun implementasi SQL Server kendala unik di hadapan NULLs tidak sesuai yang ditentukan dalam SQL Standard). Juga sebuah tabel hanya dapat memiliki satu kunci utama tetapi beberapa kendala unik.

Kedua kendala logis ini diimplementasikan secara fisik dengan indeks yang unik. Jika tidak ditentukan secara eksplisit, maka PRIMARY KEYakan menjadi indeks berkerumun dan kendala unik yang tidak berkerumun tetapi perilaku ini dapat diganti dengan menentukan CLUSTEREDatau NONCLUSTEREDsecara eksplisit dengan deklarasi kendala (Contoh sintaks)

DECLARE @T TABLE
(
A INT NULL UNIQUE CLUSTERED,
B INT NOT NULL PRIMARY KEY NONCLUSTERED
)

Sebagai hasil dari di atas indeks berikut ini dapat secara implisit dibuat pada variabel tabel di SQL Server 2000 - 2012.

+-------------------------------------+-------------------------------------+
|             Index Type              | Can be created on a table variable? |
+-------------------------------------+-------------------------------------+
| Unique Clustered Index              | Yes                                 |
| Nonunique Clustered Index           |                                     |
| Unique NCI on a heap                | Yes                                 |
| Non Unique NCI on a heap            |                                     |
| Unique NCI on a clustered index     | Yes                                 |
| Non Unique NCI on a clustered index | Yes                                 |
+-------------------------------------+-------------------------------------+

Yang terakhir membutuhkan sedikit penjelasan. Dalam tabel definisi variabel di awal jawaban ini indeks non clustered non unikName disimulasikan oleh indeks unik on Name,Id(ingat bahwa SQL Server akan diam-diam menambahkan kunci indeks clustered ke kunci NCI non unik pula).

Indeks IDENTITYkluster yang tidak unik juga dapat dicapai dengan menambahkan kolom secara manual untuk bertindak sebagai pemisah.

DECLARE @T TABLE
(
A INT NULL,
B INT NULL,
C INT NULL,
Uniqueifier INT NOT NULL IDENTITY(1,1),
UNIQUE CLUSTERED (A,Uniqueifier)
)

Tapi ini bukan simulasi yang akurat tentang bagaimana indeks berkerumun non unik biasanya sebenarnya diimplementasikan dalam SQL Server karena ini menambahkan "Uniqueifier" ke semua baris. Bukan hanya mereka yang membutuhkannya.

Martin Smith
sumber
1
Catatan: solusi 2000-2012 hanya berfungsi jika kolom teks <= 900 byte. yaitu. varchar (900), nvarchar (450)
Andre Figueiredo
1
@AndreFigueiredo ya, itu ukuran maksimum untuk kunci indeks pada tabel permanen juga dalam versi tersebut.
Martin Smith
1
Saya hanya ingin mencatat bahwa jawaban SQL 2014 bekerja dengan baik di Azure. Martin terima kasih!
Jaxidian
13

Harus dipahami bahwa dari sudut pandang kinerja tidak ada perbedaan antara tabel @temp dan tabel #temp yang mendukung variabel. Mereka berada di tempat yang sama (tempdb) dan diimplementasikan dengan cara yang sama. Semua perbedaan muncul dalam fitur tambahan. Lihat artikel lengkap yang luar biasa ini: /dba/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386

Meskipun ada kasus di mana tabel temp tidak dapat digunakan seperti dalam tabel atau fungsi skalar, untuk sebagian besar kasus lain sebelum v2016 (di mana bahkan indeks yang difilter dapat ditambahkan ke variabel tabel) Anda cukup menggunakan tabel #temp.

Kelemahan untuk menggunakan indeks bernama (atau kendala) di tempdb adalah bahwa nama-nama tersebut kemudian dapat berbenturan. Tidak hanya secara teoritis dengan prosedur lain tetapi seringkali cukup mudah dengan contoh lain dari prosedur itu sendiri yang akan mencoba untuk menempatkan indeks yang sama pada salinan tabel #temp.

Untuk menghindari bentrokan nama, hal seperti ini biasanya berfungsi:

declare @cmd varchar(500)='CREATE NONCLUSTERED INDEX [ix_temp'+cast(newid() as varchar(40))+'] ON #temp (NonUniqueIndexNeeded);';
exec (@cmd);

Ini memastikan nama selalu unik bahkan antara eksekusi simultan dari prosedur yang sama.

bielawski
sumber
Ia memiliki satu braket yang hilang setelah varchar (40), tambahkan itu
Tejasvi Hegde
1
Tidak ada masalah dengan indeks bernama - indeks hanya harus secara unik disebutkan dalam tabel. Masalahnya adalah dengan kendala yang dinamai dan solusi terbaik umumnya adalah tidak menamai mereka dalam tabel temp - kendala bernama mencegah caching objek tabel temp.
Martin Smith
1
Itu harus benar hanya untuk versi tertentu (jika itu benar untuk versi apa pun). Saya harus menemukan solusi ini secara khusus karena saya melacak kegagalan ke bentrokan indeks bernama selama eksekusi simultan.
bielawski
@bielawski Apakah Anda menggunakan 2016? Saya sangat ingin tahu apakah indeks bernama pada tabel temp adalah risiko untuk lingkungan bersamaan.
Elaskanator
1
@ Alaskaator ya, benar. Kami menemukan pertengkaran dalam tabel data meta SQL ketika sedang dimuat, menghapus nama indeks menyelesaikan masalah. Ini adalah SQL 2016.
Dan Def
0

Jika variabel Tabel memiliki data besar, maka alih-alih variabel tabel (@table) membuat tabel temp (#table). Variabel tabel tidak memungkinkan untuk membuat indeks setelah dimasukkan.

 CREATE TABLE #Table(C1 int,       
  C2 NVarchar(100) , C3 varchar(100)
  UNIQUE CLUSTERED (c1) 
 ); 
  1. Buat tabel dengan indeks berkerumun unik

  2. Masukkan data ke dalam tabel "#Table" Temp

  3. Buat indeks yang tidak berkerumun.

     CREATE NONCLUSTERED INDEX IX1  ON #Table (C2,C3);
Boopathi.Indotnet
sumber
buat indeks setelah memasukkan pernyataan untuk menghindari penyortiran yang tidak perlu
Boopathi.Indotnet
Perhatikan bahwa ini tidak mungkin jika variabel tabel dalam suatu fungsi
Geoff