ดัชนีของ SQL Server - น้อยไปหามากหรือจากมากไปหาน้อย


138

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


1
ข้อผิดพลาดจากมากไปน้อยดัชนี: richardfoote.wordpress.com/category/descending-indexesและjonathanlewis.wordpress.com/2015/07/17/descending-indexes
Vadzim

คำตอบ:


136

สิ่งนี้สำคัญที่สุดเมื่อใช้กับดัชนีคอมโพสิต:

CREATE INDEX ix_index ON mytable (col1, col2 DESC);

สามารถใช้ได้ทั้ง:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2 DESC

หรือ:

SELECT  *
FROM    mytable
ORDER BY
        col1 DESC, col2

แต่ไม่ใช่สำหรับ:

SELECT  *
FROM    mytable
ORDER BY
        col1, col2

ดัชนีในคอลัมน์เดียวสามารถใช้อย่างมีประสิทธิภาพสำหรับการเรียงลำดับทั้งสองวิธี

ดูบทความในบล็อกของฉันสำหรับรายละเอียด:

ปรับปรุง:

ในความเป็นจริงสิ่งนี้อาจมีความสำคัญสำหรับดัชนีคอลัมน์เดียวแม้ว่าจะไม่ชัดเจนก็ตาม

ลองนึกภาพดัชนีในคอลัมน์ของตารางคลัสเตอร์:

CREATE TABLE mytable (
       pk INT NOT NULL PRIMARY KEY,
       col1 INT NOT NULL
)
CREATE INDEX ix_mytable_col1 ON mytable (col1)

ดัชนีการcol1เก็บค่าสั่งซื้อcol1พร้อมกับการอ้างอิงไปยังแถว

pkตั้งแต่ตารางคลัสเตอร์อ้างอิงถึงแถวเป็นจริงค่าของ col1พวกเขาจะได้รับคำสั่งยังอยู่ในค่าของแต่ละ

ซึ่งหมายความว่าจะมีการสั่งให้ออกจากดัชนีจริง ๆ(col1, pk)และแบบสอบถามนี้:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk

ไม่ต้องการเรียงลำดับ

ถ้าเราสร้างดัชนีดังต่อไปนี้:

CREATE INDEX ix_mytable_col1_desc ON mytable (col1 DESC)

จากนั้นค่าของcol1จะเรียงลำดับจากมากไปน้อย แต่ค่าของpkภายในแต่ละค่าของcol1จะเรียงลำดับจากน้อยไปมาก

ซึ่งหมายความว่าแบบสอบถามต่อไปนี้:

SELECT  col1, pk
FROM    mytable
ORDER BY
        col1, pk DESC

สามารถเสิร์ฟแต่ไม่ได้โดยix_mytable_col1_descix_mytable_col1

กล่าวอีกนัยหนึ่งคอลัมน์ที่ประกอบขึ้นเป็นCLUSTERED INDEXตารางใด ๆ จะเป็นคอลัมน์ต่อท้ายของดัชนีอื่น ๆ ในตารางนั้นเสมอ


1
เมื่อคุณพูดว่า "ไม่ได้สำหรับ ... " คุณหมายถึงว่ามันจะไม่ทำงานหรือการแสดงจะแย่มาก?
Neil N

5
ฉันหมายความว่าดัชนีจะไม่ถูกใช้สำหรับการสืบค้น แน่นอนแบบสอบถามจะใช้งานได้ แต่ประสิทธิภาพจะไม่ดี
Quassnoi

1
ในส่วนแรกตัวอย่างที่สองไม่ควรพูดว่า "สั่งซื้อโดย col1 DESC, col2 DESC" หรือไม่
มิทช์ข้าวสาลี

71

สำหรับดัชนีคอลัมน์เดี่ยวที่แท้จริงมันสร้างความแตกต่างเล็กน้อยจากมุมมองของ Query Optimizer

สำหรับคำนิยามตาราง

CREATE TABLE T1( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] ASC))

คำค้นหา

SELECT TOP 10 *
FROM T1
ORDER BY ID DESC

ใช้การสแกนตามสั่งพร้อมทิศทางการสแกนBACKWARDตามที่เห็นในแผนปฏิบัติการ มีความแตกต่างเล็กน้อย แต่ในปัจจุบันFORWARDนั้นสามารถสแกนแบบขนานเท่านั้น

วางแผน

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

ดูผลการกระจายตัวของ

                    avg_fragmentation                    avg_fragment
name   page_count   _in_percent         fragment_count   _size_in_pages
------ ------------ ------------------- ---------------- ---------------
T1     1000         0.4                 5                200
T2     1000         99.9                1000             1

สำหรับสคริปต์ด้านล่าง

/*Uses T1 definition from above*/
SET NOCOUNT ON;

CREATE TABLE T2( [ID] [int] IDENTITY NOT NULL,
                 [Filler] [char](8000) NULL,
                 PRIMARY KEY CLUSTERED ([ID] DESC))

BEGIN TRAN

GO
INSERT INTO T1 DEFAULT VALUES
GO 1000
INSERT INTO T2 DEFAULT VALUES
GO 1000

COMMIT

SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T1'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 
UNION ALL 
SELECT object_name(object_id) AS name, 
       page_count, 
       avg_fragmentation_in_percent, 
       fragment_count, 
       avg_fragment_size_in_pages 
FROM 
sys.dm_db_index_physical_stats(db_id(), object_id('T2'), 1, NULL, 'DETAILED') 
WHERE  index_level = 0 

เป็นไปได้ที่จะใช้แท็บผลลัพธ์เชิงพื้นที่เพื่อตรวจสอบการคาดคะเนว่าเป็นเพราะหน้าต่อมามีการขึ้นค่าคีย์ในทั้งสองกรณี

SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T1
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )
UNION ALL
SELECT page_id,
       [ID],
       geometry::Point(page_id, [ID], 0).STBuffer(4)
FROM   T2
       CROSS APPLY sys.fn_PhysLocCracker( %% physloc %% )

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


ขอบคุณมาร์ตินสำหรับเคล็ดลับที่ยอดเยี่ยมนี่ช่วยฉันได้มากในการจัดอันดับ
TheGameiswar

ฉันสงสัยว่าฉันมีดัชนีจากมากไปน้อยหรือไม่ให้เลือก mycolumn จาก mytable โดยที่ indexed_column = \ @myvalue เร็วขึ้นเมื่อ \ @ myvalue ใกล้เคียงกับค่าสูงสุดที่เป็นไปได้มากกว่าในกรณีที่ \ @myvalue ใกล้เคียงกับค่าต่ำสุดที่เป็นไปได้
Lajos Arpad

@ LajosArpad ทำไมจะเร็วกว่านี้ ต้นไม้ B เป็นต้นไม้ที่มีความสมดุล ความลึกของต้นไม้เหมือนกันทั้งคู่
Martin Smith

@ มาร์ตินด้วยความลึกเหมือนกัน แต่ฉันสงสัยว่าคำสั่งของพี่น้องจะไม่สร้างความแตกต่าง
Lajos Arpad

@MartinSmith หากคำสั่งของพี่น้องมีความแตกต่างกันเล็กน้อยในการแสดงผลการใช้งานตัวเลือกนับล้านจะเพิ่มขึ้นไม่ต้องพูดถึงการรวมหลายมิติ
Lajos Arpad

8

ลำดับการจัดเรียงนั้นสำคัญเมื่อคุณต้องการดึงข้อมูลที่เรียงลำดับจำนวนมากไม่ใช่ข้อมูลแต่ละระเบียน

โปรดทราบว่า (ตามที่คุณแนะนำด้วยคำถามของคุณ) โดยทั่วไปแล้วการเรียงลำดับนั้นมีความสำคัญน้อยกว่าคอลัมน์ใดที่คุณกำลังจัดทำดัชนี (ระบบสามารถอ่านดัชนีในทางกลับกันหากคำสั่งนั้นตรงข้ามกับที่ต้องการ) ฉันไม่ค่อยให้ลำดับการจัดเรียงของดัชนีความคิดใด ๆ ในขณะที่ฉันรู้สึกทรมานมากกว่าคอลัมน์ที่ครอบคลุมโดยดัชนี

@Quassnoi มีตัวอย่างที่ดีของเมื่อมันไม่เป็นเรื่อง

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