การสร้างดัชนีที่ไม่เป็นคลัสเตอร์บน SQL Server ที่คำนวณแบบไม่คอลัมน์


10

ฉันกำลังดิ้นรนเพื่อค้นหาเอกสารใด ๆ เกี่ยวกับวิธีที่ SQL Server จัดเก็บคอลัมน์ที่คำนวณได้แบบไม่ยืนยัน

นำตัวอย่างต่อไปนี้:

--SCHEMA
CREATE TABLE dbo.Invoice
(
    InvoiceID INT IDENTITY(1, 1) PRIMARY KEY,
    CustomerID INT FOREIGN KEY REFERENCES dbo.Customer(CustomerID),
    InvoiceStatus NVARCHAR(50) NOT NULL,
    InvoiceStatusID AS CASE InvoiceStatus 
                         WHEN 'Sent' THEN 1 
                         WHEN 'Complete' THEN 2
                         WHEN 'Received' THEN 3
                       END
)
GO

--INDEX
CREATE NONCLUSTERED INDEX IX_Invoice ON Invoice
(
    CustomerID ASC
)
INCLUDE
(
    InvoiceStatusID
)
GO

ฉันได้รับมันถูกเก็บไว้ที่ระดับลีฟ แต่ถ้าค่าไม่คงอยู่จะเก็บไว้ได้อย่างไร? ดัชนีช่วย SQL Server ค้นหาแถวเหล่านี้ในสถานการณ์นี้ได้อย่างไร

ความช่วยเหลือใด ๆ ที่ชื่นชมอย่างมาก

ขอบคุณมาก,

แก้ไข:

ขอบคุณ Brent & Aaron ที่ตอบคำถามนี้นี่คือ PasteThePlanอย่างชัดเจนซึ่งแสดงสิ่งที่พวกเขาอธิบาย


5
มันไม่ได้ยังคงอยู่ในหน้าข้อมูลของตาราง แต่ก็จะยังคงอยู่ในหน้าของดัชนี
Aaron Bertrand

คอลัมน์ที่คำนวณแบบไม่คงที่จะไม่ถูกจัดเก็บทางกายภาพในตาราง เป็นคอลัมน์เสมือน ค่าของพวกเขาจะคำนวณใหม่ทุกครั้งที่มีการอ้างอิงในแบบสอบถาม ดูอ้างอิงนี้
Kin Shah

คำตอบ:


11

เมื่อ SQL Server สร้างดัชนีบนเขตข้อมูลที่คำนวณแล้วเขตข้อมูลจากการคำนวณจะถูกเขียนไปยังดิสก์ในเวลานั้น แต่เฉพาะในหน้า 8K ของดัชนีนั้น SQL Server สามารถคำนวณ InvoiceStatusID ขณะที่อ่านผ่านดัชนีคลัสเตอร์ - ไม่จำเป็นต้องเขียนข้อมูลนั้นไปยังดัชนีคลัสเตอร์

ในขณะที่คุณลบ / อัปเดต / แทรกแถวใน dbo.Invoice ข้อมูลในดัชนีจะได้รับการปรับปรุงให้ทันสมัยอยู่เสมอ (เมื่อ InvoiceStatus เปลี่ยนไป SQL Server ก็รู้ว่าจะต้องปรับปรุง IX_Invoice ด้วย)

วิธีที่ดีที่สุดที่คุณสามารถเห็นได้ด้วยตัวคุณเองคือการสร้างวัตถุเหล่านี้และดำเนินการอัปเดตที่แตะฟิลด์ InvoiceStatusID โพสต์แผนการดำเนินการ (PasteThePlan.com มีประโยชน์สำหรับสิ่งนี้) หากคุณต้องการความช่วยเหลือในการดูว่าการอัพเดตดัชนีเกิดขึ้นที่ใด


1
@ Uberzen1 ไม่ตามที่อธิบายไว้มันถูกเขียนไปยังหน้าดัชนีในเวลาแทรก / อัปเดต ไม่จำเป็นต้องคำนวณอะไรอีกหากใช้ดัชนีเพื่อเข้าถึงคอลัมน์
Aaron Bertrand

อา! ฉันอยู่กับคุณตอนนี้ขอโทษ!
Uberzen1

6
@ หยดเลือดที่ดีไม่มีความผิด แต่ฉันไม่คิดว่านั่นคือเบรนต์ พวกเขาสามารถวาง XML เดียวกันลงในดรอปบ็อกซ์ฟอรัม MSDN ที่นี่โดยทั่วไปทุกที่ออนไลน์ ... ทุกบริการออนไลน์ต้องรับผิดชอบต่อความลับที่อาจเปิดเผยโดยผู้ที่อัปโหลดไฟล์ที่นั่นหรือไม่
Aaron Bertrand

2
@ blobbles ใช่คุณไม่สามารถหยุดผู้คนจากการเกินกำลัง เฮ้ตามฉันไปบน Instagram - ฉันคือเบรนท์ - และฉันแบ่งปันรูปภาพอาหารเช้าที่นั่น ;-)
Brent Ozar

4
@blobbles ในการเชื่อมโยงความเป็นส่วนตัวมันฯ : ข้อมูลที่คุณคัดลอก / วางในที่นี่เป็นที่สาธารณะ ทุกคนสามารถอ่านได้ ไม่มีความปลอดภัย
ypercubeᵀᴹ

8

ค่าสำหรับการจัดทำดัชนีที่ไม่ใช่ยืนกรานคอลัมน์คำนวณไม่ได้ยืนยันในหน้าข้อมูลของตารางแต่ก็จะยังคงอยู่ในหน้าของดัชนี มันยังคงไม่คงอยู่ในตารางโดยไม่คำนึงว่ามันจะยังคงอยู่ในดัชนี 0, 1 หรือหลาย ๆ

เพียงเพื่ออธิบายคำอธิบายของ Brent โดยนำตัวอย่างที่คุณให้มาลองแทรกแถว:

INSERT dbo.Invoice(CustomerID, InvoiceStatus) VALUES(1,N'Sent');

ตอนนี้เรามาดูหน้าดัชนี:

DBCC TRACEON(3604, -1);
DBCC IND(N'dbname', N'dbo.Invoice', 2);

(เปลี่ยนอย่างชัดเจนdbnameและรหัสดัชนีอาจไม่ใช่ 2 ในกรณีของคุณ)

ผลลัพธ์ (ของคุณจะแตกต่างกันอย่างแน่นอน):

ป้อนคำอธิบายรูปภาพที่นี่

และสุดท้ายเรามาตรวจสอบหน้าPageType2:

DBCC PAGE(7, 1, 584, 3);

(คุณอาจต้องเปลี่ยน 7 เพื่อให้ตรงกับ id ฐานข้อมูลของคุณและหากคุณมีไฟล์ข้อมูลหลายไฟล์คุณอาจต้องเปลี่ยนอาร์กิวเมนต์ที่สองเพื่อจับคู่PageFIDจากผลลัพธ์แรก)

เอาท์พุท:

ป้อนคำอธิบายรูปภาพที่นี่

นั่นคือในหน้าดัชนี


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

1
@ Uberzen1 คุณสามารถกำหนด "ปัญหาที่แท้จริง" ได้หรือไม่? คุณจะโพสต์คำถามเกี่ยวกับปัญหานั้นหรือไม่?
Aaron Bertrand

ฉันอาจจะทำฉันจะขุดเข้าไปในตัวเองมากกว่านี้ก่อน แต่เพียงแค่อยากรู้ว่าคำสั่งสร้างดัชนีกำลังทำอะไรอยู่ TLDR คือ; ฉันมีตารางขนาดใหญ่คล้ายกับตารางใบแจ้งหนี้ด้านบนมีระเบียน 400m และน่าเสียดายที่คอลัมน์ OrderStatus ตบตรงกลางของมันทำให้การจัดทำดัชนี ฯลฯ เจ็บปวดเล็กน้อย เราได้เพิ่มคอลัมน์ที่คำนวณแล้วเพื่อที่ว่าเราจะคงอยู่ในที่สุดและย้ายฟิลด์ varchar ออกไปที่ตารางของตัวเอง 1/2
Uberzen1

5
@ Uberzen1 ใช่แล้วเนื่องจากคอลัมน์ที่คำนวณนั้นจริงแล้วปรากฏขึ้นบนดิสก์เมื่อเขียนไปยังดัชนีกิจกรรมทั้งหมดจึงต้องถูกบันทึกไว้ วิธีแก้ปัญหาอาจหยุดการพึ่งพาคอลัมน์ที่คำนวณได้ - นำนิพจน์นั้นไปไว้ในมุมมองหรือคิวรีเฉพาะกิจแล้วและหากนั่นไม่ใช่ตัวเลือกที่คุณสามารถสร้างคอลัมน์ที่ไม่มีค่าได้ใหม่ให้อัปเดตเป็นกลุ่ม (เพื่อหลีกเลี่ยงการฆ่าล็อก) จากนั้นปล่อยคอลัมน์ที่คำนวณแล้วเปลี่ยนชื่อคอลัมน์ใหม่และเปลี่ยน DML ของคุณเพื่อเขียนเอง แต่จริงๆแล้วมันเป็นข้อมูลซ้ำซ้อนที่คุณสามารถหาได้จากข้อมูลที่มีอยู่ฉันจึงเลือกใช้ตัวเลือกแรก
Aaron Bertrand

2
ขอบคุณมากแอรอน ฉันดีใจที่คุณพูดถึงการแสดงความคิดเห็นต่อหน้ามันเพราะนั่นเป็นวิธีแก้ปัญหาของฉันเช่นกันบางทีมันถึงเวลาที่จะทบทวนความคิดนั้นอีกครั้ง!
Uberzen1

7

แอ็ตทริบิวต์PERSISTEDสำหรับคอลัมน์ที่คำนวณนั้นเกี่ยวข้องกับว่าค่านั้นยังคงอยู่ในตาราง (ดัชนีคลัสเตอร์หรือฮีป) และไม่ว่าค่านั้นจะคงอยู่ในดัชนีหรือไม่

CREATE INDEXมีข้อกำหนดสำหรับข้อ จำกัด เกี่ยวกับการคำนวณคอลัมน์และดัชนี:

คอลัมน์ที่คำนวณได้ซึ่งถูกกำหนดไว้แล้วและอาจรวมคอลัมน์ที่แม่นยำหรือไม่ถูกต้อง คอลัมน์ที่คำนวณได้มาจากอิมเมจ, ntext, ข้อความ, varchar (สูงสุด), nvarchar (สูงสุด), varbinary (สูงสุด), และประเภทข้อมูล xml สามารถรวมอยู่ในคอลัมน์ที่ไม่ใช่คีย์ตราบใดที่คอลัมน์ข้อมูลที่คำนวณนั้นอนุญาตให้รวม คอลัมน์. สำหรับข้อมูลเพิ่มเติมดูดัชนีในคอลัมน์ที่คำนวณ

ไม่มีข้อ จำกัด ว่าคอลัมน์ที่คำนวณนั้นจะยังคงอยู่หรือไม่

และเพิ่มเติม (ไม่ได้รวมอยู่ด้วย แต่เกี่ยวกับคอลัมน์ที่คำนวณในส่วนหลักของดัชนี):

สามารถสร้างดัชนีในคอลัมน์ที่คำนวณได้ นอกจากนี้คอลัมน์ที่คำนวณได้สามารถมีคุณสมบัติPERSISTEDได้ ซึ่งหมายความว่า Database Engine เก็บค่าที่คำนวณในตารางและอัพเดตเมื่อคอลัมน์อื่น ๆ ที่ขึ้นกับคอลัมน์ที่คำนวณนั้นถูกอัพเดต โปรแกรมฐานข้อมูลใช้ค่าที่เก็บไว้เหล่านี้เมื่อสร้างดัชนีในคอลัมน์และเมื่อมีการอ้างอิงดัชนีในแบบสอบถาม

ในการสร้างดัชนีคอลัมน์จากการคำนวณคอลัมน์ที่คำนวณต้อง (ต้อง) กำหนดและแม่นยำ อย่างไรก็ตามการใช้PERSISTEDคุณสมบัติจะขยายประเภทของคอลัมน์ที่คำนวณได้ซึ่งจัดทำดัชนีเพื่อรวม:

...

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