เพิ่มประสิทธิภาพการเข้าร่วมบนโต๊ะขนาดใหญ่


10

ฉันพยายามเกลี้ยกล่อมให้มีประสิทธิภาพมากขึ้นจากการสืบค้นที่เข้าถึงตารางที่มีระเบียน ~ 250 ล้านรายการ จากการอ่านแผนปฏิบัติการจริง (ไม่ได้ประเมิน) ของฉันคอขวดแรกคือแบบสอบถามที่มีลักษณะดังนี้:

select
    b.stuff,
    a.added,
    a.value
from
    dbo.hugetable a
    inner join
    #smalltable b on a.fk = b.pk
where
    a.added between @start and @end;

ดูเพิ่มเติมสำหรับคำจำกัดความของตารางและดัชนีที่เกี่ยวข้อง

แผนการดำเนินการบ่งชี้ว่ามีการใช้ลูปที่ซ้อนกันบน #smalltable และดัชนีการสแกนผ่าน hugetable กำลังดำเนินการ 480 ครั้ง (สำหรับแต่ละแถวใน #smalltable) สิ่งนี้ดูเหมือนจะย้อนกลับมาที่ฉันดังนั้นฉันจึงพยายามบังคับให้รวมการผสานเพื่อใช้แทน:

select
    b.stuff,
    a.added,
    a.value
from
    dbo.hugetable a with(index = ix_hugetable)
    inner merge join
    #smalltable b with(index(1)) on a.fk = b.pk
where
    a.added between @start and @end;

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

เมื่อฉันทำเช่นนี้การค้นหาจะเริ่มจาก 2 1/2 นาทีไปจนถึง 9 ฉันหวังว่าคำแนะนำจะบังคับให้มีการเข้าร่วมที่มีประสิทธิภาพมากขึ้นซึ่งทำได้เพียงครั้งเดียวผ่านแต่ละตาราง แต่ไม่ชัดเจน

คำแนะนำใด ๆ ยินดีต้อนรับ ให้ข้อมูลเพิ่มเติมหากจำเป็น

อัปเดต (2011/06/02)

หลังจากจัดทำดัชนีใหม่บนโต๊ะฉันได้ทำการแสดงที่สำคัญ ๆ แล้วอย่างไรก็ตามฉันได้เจออุปสรรคใหม่เมื่อมันมาถึงการสรุปข้อมูลในตารางขนาดใหญ่ ผลลัพธ์คือการสรุปตามเดือนซึ่งปัจจุบันมีลักษณะดังนี้:

select
    b.stuff,
    datediff(month, 0, a.added),
    count(a.value),
    sum(case when a.value > 0 else 1 end) -- this triples the running time!
from
    dbo.hugetable a
    inner join
    #smalltable b on a.fk = b.pk
group by
    b.stuff,
    datediff(month, 0, a.added);

ในปัจจุบันhugetableมีดัชนีคลัสเตอร์pk_hugetable (added, fk)(คีย์หลัก) ix_hugetable (fk, added)และดัชนีที่ไม่ใช่คลัสเตอร์ไปทางอื่น

หากไม่มีคอลัมน์ที่ 4 ด้านบนเครื่องมือเพิ่มประสิทธิภาพจะใช้การวนซ้ำแบบซ้อนกันเหมือนเดิมโดยใช้ #smalltable เป็นอินพุตด้านนอกและดัชนีที่ไม่ใช่คลัสเตอร์จะค้นหาเป็นวงใน (เรียกใช้งาน 480 ครั้ง) สิ่งที่เกี่ยวข้องกับฉันคือความแตกต่างระหว่างแถวที่ประเมิน (12,958.4) และแถวที่แท้จริง (74,668,468) ต้นทุนสัมพัทธ์ของการค้นหาเหล่านี้คือ 45% เวลาทำงานไม่เกินหนึ่งนาที

ด้วยคอลัมน์ที่ 4 เวลาในการรันจะเพิ่มขึ้นเป็น 4 นาที มันค้นหาดัชนีคลัสเตอร์ในครั้งนี้ (2 การประมวลผล) สำหรับค่าใช้จ่ายสัมพัทธ์เดียวกัน (45%) รวมผ่านการจับคู่แฮช (30%) จากนั้นทำการแฮชเข้าร่วมใน #smalltable (0%)

ฉันไม่แน่ใจว่าจะทำอะไรต่อไป ความกังวลของฉันคือไม่รับประกันการค้นหาช่วงวันที่หรือเข้าร่วมกริยาหรือแม้แต่สิ่งที่น่าจะลดชุดผลลัพธ์อย่างมาก ช่วงวันที่ในกรณีส่วนใหญ่จะตัดเพียง 10-15% ของเรคคอร์ดและการรวมภายในบนfkอาจกรองออกประมาณ 20-30%


ตามที่ขอโดย Will A ผลลัพธ์ของsp_spaceused:

name      | rows      | reserved    | data        | index_size  | unused
hugetable | 261774373 | 93552920 KB | 18373816 KB | 75167432 KB | 11672 KB

#smalltableถูกกำหนดเป็น:

create table #endpoints (
    pk uniqueidentifier primary key clustered,
    stuff varchar(6) null
);

ในขณะที่dbo.hugetableถูกกำหนดเป็น:

create table dbo.hugetable (
    id uniqueidentifier not null,
    fk uniqueidentifier not null,
    added datetime not null,
    value decimal(13, 3) not null,

    constraint pk_hugetable primary key clustered (
        fk asc,
        added asc,
        id asc
    )
    with (
        pad_index = off, statistics_norecompute = off,
        ignore_dup_key = off, allow_row_locks = on,
        allow_page_locks = on
    )
    on [primary]
)
on [primary];

ด้วยการกำหนดดัชนีต่อไปนี้:

create nonclustered index ix_hugetable on dbo.hugetable (
    fk asc, added asc, id asc
) include(value) with (
    pad_index = off, statistics_norecompute = off,
    sort_in_tempdb = off, ignore_dup_key = off,
    drop_existing = off, online = off,
    allow_row_locks = on, allow_page_locks = on
)
on [primary];

รหัสข้อมูลซ้ำซ้อน, สิ่งประดิษฐ์จาก DBA ก่อนหน้านี้ที่ยืนยันว่าทุกตารางทุกคนควรมี GUID ไม่มีข้อยกเว้น


คุณสามารถรวมผลลัพธ์ของ sp_spaceused 'dbo.hugetable' ได้ไหม
จะ

เสร็จสิ้นแล้วเพิ่มเหนือคำจำกัดความเริ่มต้นของตาราง
โจสมิ ธ ด่วน

แน่ใจ. ขนาดที่ไร้สาระของมันคือเหตุผลที่ฉันดูนี่
โจสมิ ธ ด่วน

คำตอบ:


5

ix_hugetableรูปลักษณ์ของคุณค่อนข้างไร้ประโยชน์เพราะ:

  • มันเป็นดัชนีคลัสเตอร์ (PK)
  • INCLUDE ไม่สร้างความแตกต่างเนื่องจากดัชนีคลัสเตอร์รวมคอลัมน์ที่ไม่ใช่คีย์ทั้งหมด (ค่าที่ไม่ใช่คีย์ที่ leaf ต่ำสุด = INCLUDEd = ดัชนีคลัสเตอร์คืออะไร)

นอกจากนี้: - เพิ่มหรือ fk ควรเป็นอันดับแรก - ID คือ first = ไม่ได้ใช้งานมากนัก

ลองเปลี่ยนคีย์คลัสเตอร์ไปและวาง(added, fk, id) คุณได้พยายามแล้วix_hugetable (fk, added, id)หากไม่มีสิ่งใดคุณจะประหยัดพื้นที่ดิสก์และการบำรุงรักษาดัชนีเป็นจำนวนมาก

ตัวเลือกอื่นอาจลองใช้คำแนะนำการบังคับด้วยคำสั่งตาราง boh และไม่มีคำแนะนำ JOIN / INDEX ฉันพยายามไม่ใช้คำแนะนำ JOIN / INDEX เป็นการส่วนตัวเพราะคุณลบตัวเลือกสำหรับเครื่องมือเพิ่มประสิทธิภาพ หลายปีที่ผ่านมาฉันได้รับการบอกกล่าว (การสัมมนากับปราชญ์ SQL) ว่าคำใบ้การบังคับใช้สามารถช่วยได้เมื่อคุณมีโต๊ะขนาดใหญ่เข้าร่วมโต๊ะเล็ก: YMMV 7 ปีต่อมา ...

โอ้และแจ้งให้เราทราบว่า DBA อาศัยอยู่ที่ใดเพื่อให้เราสามารถจัดปรับการกระทบบางอย่าง

แก้ไขหลังจากอัพเดต 02 มิ.ย.

คอลัมน์ที่ 4 ไม่ได้เป็นส่วนหนึ่งของดัชนีที่ไม่ทำคลัสเตอร์ดังนั้นจึงใช้ดัชนีที่ทำคลัสเตอร์

ลองเปลี่ยนดัชนี NC เพื่อรวมคอลัมน์ค่าดังนั้นจึงไม่จำเป็นต้องเข้าถึงคอลัมน์ค่าสำหรับดัชนีคลัสเตอร์

create nonclustered index ix_hugetable on dbo.hugetable (
    fk asc, added asc
) include(value)

หมายเหตุ: ถ้าค่าไม่เป็นโมฆะมันก็เหมือนกับCOUNT(*)semantically แต่สำหรับ SUM มันต้องเกิดขึ้นจริงค่าไม่ได้ดำรงอยู่

ตัวอย่างเช่นถ้าคุณเปลี่ยนCOUNT(value)เป็นCOUNT(DISTINCT value) โดยไม่มีการเปลี่ยนแปลงดัชนีมันควรทำลายแบบสอบถามอีกครั้งเพราะต้องประมวลผลค่าเป็นค่าไม่ใช่การมีอยู่

แบบสอบถามต้องการ 3 คอลัมน์: เพิ่ม, fk, ค่า 2 ตัวแรกจะถูกกรอง / เข้าร่วมดังนั้นจึงเป็นคอลัมน์สำคัญ ค่าจะถูกใช้ดังนั้นสามารถรวมได้ การใช้งานคลาสสิกของดัชนีครอบคลุม


ใช่ฉันมีมันอยู่ในหัวของฉันว่าดัชนีที่เป็นกลุ่มและไม่ใช่กลุ่มนั้นมี fk & เพิ่มขึ้นในลำดับที่แตกต่างกัน ฉันไม่อยากจะเชื่อเลยว่าไม่ได้สังเกตว่าเกือบเท่าที่ฉันไม่สามารถเชื่อได้ว่ามันเป็นการติดตั้งแบบนี้ตั้งแต่แรก ฉันจะเปลี่ยนดัชนีกลุ่มในวันพรุ่งนี้จากนั้นไปที่ถนนเพื่อซื้อกาแฟในขณะที่สร้างใหม่
Quick Joe Smith

ฉันเปลี่ยนดัชนีและทุบตีด้วย FORCE ORDER เพื่อลดจำนวนการค้นหาบนโต๊ะขนาดใหญ่ แต่ไม่มีประโยชน์ คำถามของฉันได้รับการปรับปรุง
ด่วนโจสมิ ธ

@Quick Joe Smith: อัปเดตคำตอบของฉัน
gbn

ใช่ฉันลองแล้วไม่นาน เนื่องจากการสร้างดัชนีใหม่ใช้เวลานานมากฉันจึงลืมไปและคิดว่าในขั้นต้นฉันจะเร่งทำสิ่งที่ไม่เกี่ยวข้องโดยสิ้นเชิง
Quick Joe Smith

2

กำหนดดัชนีhugetableบนเพียงaddedคอลัมน์

ฐานข้อมูลจะใช้ดัชนีหลายส่วน (หลายคอลัมน์) ทางด้านขวาสุดของรายการคอลัมน์เนื่องจากมีค่านับจากด้านซ้าย การค้นหาของคุณไม่ได้ระบุfkในส่วนคำสั่งย่อยของการสืบค้นแรกดังนั้นจึงไม่สนใจดัชนี


แผนปฏิบัติการแสดงให้เห็นว่าดัชนี (ix_hugetable) จะถูก seeked หรือคุณกำลังบอกว่าดัชนีนี้ไม่เหมาะสำหรับการสืบค้น?
โจสมิ ธ ด่วน

ดัชนีไม่เหมาะสม ใครจะรู้ว่ามันคือ "การใช้ดัชนี" ใคร ประสบการณ์บอกฉันว่านี่เป็นปัญหาของคุณ ลองและบอกเราว่ามันจะไปอย่างไร
โบฮีเมียน

@Quick Joe Smith - คุณลองใช้คำแนะนำของ @ Bohemian หรือไม่ ผลลัพธ์อยู่ที่ไหน
Lieven Keersmaekers

2
ฉันไม่เห็นด้วย: ประโยค ON ถูกประมวลผลอย่างมีเหตุผลก่อนและเป็น WHERE ที่ใช้ได้จริงดังนั้น OP ต้องลองทั้งสองคอลัมน์ก่อน ไม่มีการทำดัชนีบน fk at all = การสแกนดัชนีแบบคลัสเตอร์หรือค้นหาคีย์เพื่อรับค่า fk สำหรับ JOIN คุณสามารถเพิ่มการอ้างอิงบางอย่างให้กับพฤติกรรมที่คุณอธิบายได้ด้วยหรือไม่ โดยเฉพาะอย่างยิ่งสำหรับ SQL Server เนื่องจากคุณมีประวัติการตอบรับก่อนหน้านี้เล็กน้อยสำหรับ RDBMS นี้ ที่จริงแล้ว -1 ในการหวนกลับเป็น aI พิมพ์ความคิดเห็นนี้
gbn

2

แผนการดำเนินการบ่งชี้ว่ามีการใช้ลูปที่ซ้อนกันบน #smalltable และดัชนีการสแกนผ่าน hugetable กำลังดำเนินการ 480 ครั้ง (สำหรับแต่ละแถวใน #smalltable)

นี่คือลำดับที่ฉันต้องการให้เครื่องมือเพิ่มประสิทธิภาพการสืบค้นใช้สมมติว่าการวนซ้ำเข้าร่วมในตัวเลือกที่เหมาะสม ทางเลือกคือการวนซ้ำ 250M และทำการค้นหาในตาราง #temp แต่ละครั้ง - ซึ่งอาจใช้เวลาหลายชั่วโมง / วัน

ดัชนีที่คุณบังคับให้ใช้ในการเข้าร่วม MERGE นั้นมีขนาด 250M แถว * 'ขนาดของแต่ละแถว' - ไม่เล็กอย่างน้อยสอง GB การตัดสินจากsp_spaceusedเอาต์พุต 'สอง GB' อาจจะค่อนข้างไม่เพียงพอ - การเข้าร่วม MERGE นั้นคุณต้องสืบค้นผ่านดัชนีซึ่งจะต้องใช้ I / O มาก


ความเข้าใจของฉันคือการมีอัลกอริทึมการเข้าร่วม 3 ประเภทและการรวมการเข้าร่วมมีประสิทธิภาพที่ดีที่สุดเมื่อทั้งสองอินพุทเข้ารับคำสั่งจากภาคผนวกการเข้าร่วม ถูกหรือผิดนี่คือผลลัพธ์ที่ฉันได้รับ
โจสมิ ธ ด่วน

2
แต่มีมากกว่านั้น ถ้า #smalltable มีแถวจำนวนมากการรวมการผสานอาจเหมาะสม ถ้าตามชื่อแนะนำมันมีจำนวนแถวน้อยดังนั้นการรวมแบบวนรอบอาจเป็นตัวเลือกที่เหมาะสม ลองนึกภาพว่า #smalltable มีหนึ่งหรือสองแถวและจับคู่กับแถวจำนวนหนึ่งจากตารางอื่น - เป็นการยากที่จะแสดงให้เห็นว่าการรวมการเข้าร่วมที่นี่
จะ

ฉันคิดว่ามันมีมากกว่านั้น ฉันไม่รู้ว่ามันอาจจะเป็นอะไร การปรับฐานข้อมูลไม่เหมาะกับฉันอย่างที่คุณคาดเดาไว้
โจสมิ ธ ด่วน

@ Quick Joe Smith - ขอบคุณสำหรับ sp_spaceused 75GB ของดัชนีและ 18GB ของข้อมูล - ix_hugetable ไม่ได้เป็นเพียงดัชนีในตารางหรือไม่?
จะ

1
+1 จะ ผู้วางแผนกำลังทำสิ่งที่ถูกต้อง ปัญหาอยู่ในการค้นหาดิสก์แบบสุ่มเนื่องจากวิธีการจัดกลุ่มตารางของคุณ
Denis de Bernardy

1

ดัชนีของคุณไม่ถูกต้อง ดูดอสดัชนีและ Donts

ดัชนีของคุณมีประโยชน์เพียงอย่างเดียวคือในคีย์หลักของตารางเล็ก ๆ แผนเดียวที่สมเหตุสมผลคือการสแกนตารางเล็ก ๆ และทำรังให้ยุ่งกับตารางขนาดใหญ่

hugetable(added, fk)ลองเพิ่มดัชนีคลัสเตอร์บน สิ่งนี้ควรทำให้ผู้วางแผนค้นหาแถวที่เกี่ยวข้องจากตารางขนาดใหญ่และซ้อนซ้อนหรือผสานเข้ากับตารางขนาดเล็ก


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