การสร้างดัชนีในตัวแปรตาราง


190

คุณสามารถสร้างดัชนีบนตัวแปรตารางใน SQL Server 2000 ได้หรือไม่?

กล่าวคือ

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

ฉันสามารถสร้างดัชนีได้Nameหรือไม่


3
มีค่าใช้จ่ายในการสร้างตารางชั่วคราวทั้งสองชนิด และถ้าคุณมีข้อมูลจำนวนมากในการที่คุณต้องการดัชนีอาจถึงเวลาที่จะใช้ตารางจริง ที่คุณตั้งค่าให้เป็นธุรกรรมที่ปลอดภัย กรองโดย spid หรือ id ผู้ใช้แล้วล้างมันในตอนท้าย ตารางจริง v ตารางชั่วคราวมีทั้งแบบขึ้นและลง แต่ถ้าประสิทธิภาพเป็นปัญหา ลองกับตารางจริงด้วย
u07ch

ตารางอุณหภูมิ 'IS' เป็นตารางจริงมันจะหายไปเมื่อคุณทำเสร็จ ความแตกต่างที่แท้จริง (นอกเหนือจากที่มันจะหายไปโดยอัตโนมัติ) คือมันอยู่ใน TempDB นี่เป็นเรื่องที่ใหญ่มากเมื่อพูดถึงดัชนีและข้อ จำกัด เพราะคุณสามารถจบลงด้วยการปะทะกันของชื่อไม่เพียง แต่การประมวลผลรหัสอื่น ๆ ของคุณเท่านั้น แต่ยังมีการใช้รหัสในฐานข้อมูลอื่นในอินสแตนซ์ของคุณ
bielawski

@bielawski นี่เป็นตัวแปรตารางไม่ใช่ตารางชั่วคราว ตัวแปรตารางไม่อนุญาตให้มีข้อ จำกัด ที่ระบุชื่ออย่างชัดเจนชื่อที่ระบบสร้างขึ้นรับประกันว่าจะไม่ซ้ำกัน พวกเขาอนุญาตดัชนีที่มีชื่อตั้งแต่ปี 2014 แต่นั่นไม่ใช่ปัญหาเนื่องจากดัชนีจะต้องตั้งชื่อเฉพาะภายในวัตถุที่ไม่ได้ข้ามวัตถุ
Martin Smith

ประเด็นของฉันคือ 2 เท่า 1) นอกเหนือจากการใช้ตัวแปรเพื่อหลีกเลี่ยงความยุ่งเหยิงการทำธุรกรรมไม่มีความแตกต่างอย่างมีนัยสำคัญระหว่างตารางชั่วคราวและตัวแปรตาราง ใน V-2000 อย่างไรก็ตามไม่มีไวยากรณ์สำหรับการเพิ่มข้อ จำกัด ดัชนี ... ไปยังตัวแปร 2) ให้ใครสามารถใช้ตาราง temp แทนชื่อตารางภาคผนวกเช่นดัชนีจะขัดแย้งกับการดำเนินการสำเนา SP เดียวกันพร้อมกันถ้าใช้ชื่อคงที่! กลไกด้านล่างนี้ได้รับการพัฒนาอย่างชัดเจนเพราะฉันตรวจสอบความล้มเหลวของ SP ในการตั้งชื่อดัชนีที่ขัดแย้งกันในระหว่างสถานการณ์ที่แน่นอนเหล่านี้ พวกเขาจะต้องไม่ซ้ำกัน
bielawski

1
@bielawski - ชื่อดัชนีไม่จำเป็นต้องไม่ซ้ำกันระหว่างวัตถุ - เฉพาะชื่อข้อ จำกัด เท่านั้น นี่เป็นเรื่องเล็กน้อยที่จะทดสอบ เพิ่งดำเนินการCREATE TABLE #T1(X INT); CREATE TABLE #T2(X INT); CREATE INDEX IX ON #T1(X); CREATE INDEX IX ON #T2(X);
Martin Smith

คำตอบ:


363

คำถามถูกติดแท็ก SQL Server 2000 แต่เพื่อประโยชน์ของผู้ที่กำลังพัฒนาในเวอร์ชั่นล่าสุดฉันจะพูดถึงเรื่องนี้ก่อน

SQL Server 2014

นอกเหนือจากวิธีการเพิ่มดัชนีตามข้อ จำกัด ที่กล่าวถึงด้านล่าง SQL Server 2014 ยังอนุญาตให้ระบุดัชนีที่ไม่ซ้ำกันโดยตรงด้วยไวยากรณ์แบบอินไลน์ในการประกาศตัวแปรตาราง

ตัวอย่างไวยากรณ์สำหรับที่อยู่ด้านล่าง

/*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*/
);

ดัชนีและดัชนีที่กรองพร้อมคอลัมน์ที่รวมอยู่ในขณะนี้ไม่สามารถประกาศด้วยไวยากรณ์นี้ได้ในขณะนี้ แต่SQL Server 2016จะช่วยให้ผ่อนคลายได้อีกเล็กน้อย จาก CTP 3.1 เป็นไปได้ที่จะประกาศดัชนีตัวกรองสำหรับตัวแปรตาราง โดย RTM อาจเป็นกรณีที่อนุญาตให้มีคอลัมน์ที่รวมอยู่ด้วย แต่ตำแหน่งปัจจุบันคือพวกเขา"จะไม่ทำให้เป็น SQL16 เนื่องจากข้อ จำกัด ของทรัพยากร"

/*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

ฉันสามารถสร้างดัชนีในชื่อได้หรือไม่

คำตอบสั้น ๆ : ใช่

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

คำตอบโดยละเอียดเพิ่มเติมอยู่ด้านล่าง

ตารางแบบดั้งเดิมใน SQL Server สามารถมีดัชนีคลัสเตอร์หรือมีโครงสร้างเป็นกอง

ดัชนีแบบกลุ่มสามารถถูกประกาศให้เป็นค่าที่ไม่ซ้ำกันเพื่อไม่อนุญาตให้ใช้ค่าคีย์ที่ซ้ำกันหรือค่าดีฟอลต์เป็นแบบไม่ซ้ำกัน หากไม่ซ้ำกันแล้ว SQL Server จะเพิ่มตัวระบุที่ไม่ซ้ำกันไปยังคีย์ที่ซ้ำกันเพื่อทำให้เป็นเอกลักษณ์

ดัชนีที่ไม่ใช่คลัสเตอร์ยังสามารถประกาศอย่างชัดเจนว่าไม่ซ้ำกัน มิฉะนั้นสำหรับกรณีที่ไม่ซ้ำกัน SQL Server จะเพิ่มตัวระบุแถว (คีย์ดัชนีคลัสเตอร์หรือRIDสำหรับฮีป) ให้กับคีย์ดัชนีทั้งหมด (ไม่เพียง แต่ซ้ำกัน) สิ่งนี้ทำให้แน่ใจได้ว่าพวกเขาจะไม่ซ้ำกัน

ใน SQL Server 2000 - 2012 ดัชนีบนตัวแปรตารางสามารถสร้างได้โดยปริยายโดยการสร้าง UNIQUEหรือPRIMARY KEYข้อ จำกัด ความแตกต่างระหว่างประเภทข้อ จำกัด เหล่านี้คือคีย์หลักต้องอยู่ในคอลัมน์ที่ไม่สามารถลบล้างได้ คอลัมน์ที่เข้าร่วมในข้อ จำกัด ที่ไม่ซ้ำกันอาจเป็นโมฆะ (แม้ว่า SQL Server จะมีข้อ จำกัด ที่ไม่ซ้ำกันในการปรากฏตัวของNULLs ไม่ได้เป็นไปตามที่ระบุไว้ใน SQL Standard) นอกจากนี้ตารางสามารถมีคีย์หลักได้เพียงคีย์เดียว แต่มีข้อ จำกัด ที่ไม่ซ้ำกันหลายข้อ

ข้อ จำกัด เชิงตรรกะทั้งสองนี้มีการใช้งานทางกายภาพด้วยดัชนีที่ไม่ซ้ำกัน หากไม่ได้ระบุไว้อย่างชัดเจนมิฉะนั้นPRIMARY KEYจะกลายเป็นดัชนีที่เป็นคลัสเตอร์และข้อ จำกัด ที่ไม่ซ้ำกันซึ่งไม่ได้ทำคลัสเตอร์ แต่พฤติกรรมนี้สามารถถูกแทนที่ได้ด้วยการระบุCLUSTEREDหรือNONCLUSTEREDชัดเจนด้วยการประกาศข้อ จำกัด

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

อันเป็นผลมาจากดัชนีข้างต้นสามารถสร้างขึ้นโดยปริยายบนตัวแปรตารางใน 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                                 |
+-------------------------------------+-------------------------------------+

อันสุดท้ายต้องใช้คำอธิบายเล็กน้อย ในคำนิยามตัวแปรตารางที่จุดเริ่มต้นของคำตอบนี้ดัชนีที่ไม่ใช่แบบคลัสเตอร์ที่ไม่ซ้ำกันNameจะถูกจำลองโดยดัชนีเฉพาะบนName,Id(จำได้ว่า SQL Server จะเพิ่มคีย์ดัชนีแบบคลัสเตอร์ในคีย์ NCI ที่ไม่ซ้ำกันอยู่แล้ว)

ดัชนีคลัสเตอร์ที่ไม่ซ้ำกันสามารถทำได้โดยการเพิ่มIDENTITYคอลัมน์เพื่อทำหน้าที่เป็นตัวระบุ

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

แต่นี่ไม่ใช่การจำลองที่แม่นยำของวิธีการที่ดัชนีที่ไม่ซ้ำแบบคลัสเตอร์จะนำไปใช้งานจริงใน SQL Server ตามจริงซึ่งเป็นการเพิ่ม "Uniqueifier" ให้กับแถวทั้งหมด ไม่ใช่แค่คนที่ต้องการมัน


1
หมายเหตุ: โซลูชัน 2000-2012 ใช้ได้เฉพาะเมื่อคอลัมน์ข้อความ <= 900 ไบต์ กล่าวคือ varchar (900), nvarchar (450)
Andre Figueiredo

1
@AndreFigueired ก่อนหน้านี้นั่นเป็นขนาดสูงสุดสำหรับคีย์ดัชนีในตารางถาวรเช่นกันในเวอร์ชันเหล่านั้น
Martin Smith

1
ฉันแค่อยากจะทราบว่าคำตอบ SQL 2014 ทำงานได้ดีใน Azure ขอบคุณมาร์ติน!
Jaxidian

13

ควรเข้าใจว่าจากจุดยืนประสิทธิภาพไม่มีความแตกต่างระหว่างตาราง @temp และตาราง #temp ที่สนับสนุนตัวแปร พวกเขาอาศัยอยู่ในสถานที่เดียวกัน (tempdb) และดำเนินการในลักษณะเดียวกัน ความแตกต่างทั้งหมดปรากฏในคุณสมบัติเพิ่มเติม ดูการเขียนที่สมบูรณ์แบบน่าอัศจรรย์: /dba/16385/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server/16386#16386

แม้ว่าจะมีหลายกรณีที่ไม่สามารถใช้ตารางชั่วคราวเช่นในฟังก์ชันตารางหรือสเกลาร์สำหรับกรณีอื่น ๆ ส่วนใหญ่ก่อนหน้าปี 2016 (ซึ่งแม้แต่ดัชนีที่กรองสามารถเพิ่มลงในตัวแปรตาราง) คุณสามารถใช้ตาราง #temp

ข้อเสียเปรียบที่จะใช้ดัชนีที่มีชื่อ (หรือข้อ จำกัด ) ใน tempdb คือชื่อนั้นสามารถปะทะกัน ไม่ใช่เพียงแค่ในทางทฤษฎีกับโพรซีเดอร์อื่น ๆ แต่มักจะค่อนข้างง่ายกับอินสแตนซ์อื่น ๆ ของโพรซีเดอร์ซึ่งจะพยายามวางดัชนีเดียวกันลงบนสำเนาของตาราง #temp

เพื่อหลีกเลี่ยงการปะทะกันของชื่อบางอย่างเช่นนี้มักใช้งานได้:

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

สิ่งนี้ทำให้มั่นใจได้ว่าชื่อจะไม่ซ้ำกันเสมอแม้ในระหว่างการดำเนินการโพรซีเดอร์เดียวกันพร้อมกัน


มันมีวงเล็บหนึ่งอันที่หายไปหลังจาก varchar (40) เพิ่มนั่น
Tejasvi Hegde

1
ไม่มีปัญหากับดัชนีที่มีชื่อ - ดัชนีจะต้องมีชื่อเฉพาะภายในตาราง ปัญหาเกิดขึ้นกับข้อ จำกัด ที่ตั้งชื่อและทางออกที่ดีที่สุดโดยทั่วไปไม่ได้ตั้งชื่อไว้ในตารางชั่วคราว - ข้อ จำกัด ที่มีชื่อป้องกันการแคชวัตถุตารางชั่วคราว
Martin Smith

1
ต้องเป็นจริงสำหรับบางเวอร์ชันเท่านั้น (หากเป็นจริงสำหรับเวอร์ชันใด ๆ ) ฉันต้องหาวิธีแก้ปัญหานี้โดยเฉพาะเพราะฉันตรวจสอบความล้มเหลวของ sp ในการปะทะของดัชนีที่มีชื่อในระหว่างการดำเนินการพร้อมกัน
bielawski

@bielawski คุณใช้ 2016 หรือไม่? ฉันอยากรู้มากเกี่ยวกับว่าดัชนีที่มีชื่อในตารางอุณหภูมิมีความเสี่ยงสำหรับสภาพแวดล้อมที่เกิดขึ้นพร้อมกัน
Elaskanator

1
@Elaskanator ใช่พวกเขาเป็น เราพบความขัดแย้งในตารางข้อมูลเมตาของ SQL เมื่ออยู่ภายใต้การโหลดการลบชื่อของดัชนีจะช่วยแก้ปัญหาได้ นี่คือ SQL 2016
ด่าน Def

0

หากตัวแปร Table มีข้อมูลขนาดใหญ่ดังนั้นแทนที่จะเป็นตัวแปร table (@table) สร้างตัวแปร temp table (#table) .table ตัวแปรไม่อนุญาตให้สร้างดัชนีหลังการแทรก

 CREATE TABLE #Table(C1 int,       
  C2 NVarchar(100) , C3 varchar(100)
  UNIQUE CLUSTERED (c1) 
 ); 
  1. สร้างตารางด้วยดัชนีคลัสเตอร์ที่ไม่ซ้ำกัน

  2. แทรกข้อมูลลงในตาราง "#Table" ชั่วคราว

  3. สร้างดัชนีที่ไม่ได้ทำคลัสเตอร์

     CREATE NONCLUSTERED INDEX IX1  ON #Table (C2,C3);

สร้างดัชนีหลังจากแทรกคำสั่งเพื่อหลีกเลี่ยงการเรียงลำดับที่ไม่จำเป็น
38745

โปรดทราบว่านี่เป็นไปไม่ได้หากตัวแปรตารางอยู่ในฟังก์ชัน
Geoff
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.