Oracle ไม่ได้ใช้ดัชนีที่ไม่ซ้ำสำหรับคีย์แบบยาว


16

ฉันมีตารางที่มีแถว 250K ในฐานข้อมูลการทดสอบของฉัน (มีการผลิตอยู่สองสามร้อยล้านล้านเราสามารถสังเกตปัญหาเดียวกันได้) ตารางมีตัวระบุสตริง nvarchar2 (50) ไม่ใช่ null โดยมีดัชนีที่ไม่ซ้ำกัน (ไม่ใช่ PK)

ตัวระบุประกอบด้วยส่วนแรกที่มี 8 ค่าที่แตกต่างกันในฐานข้อมูลการทดสอบของฉัน (และประมาณหนึ่งพันครั้งในการผลิต) จากนั้นเครื่องหมาย @ และในที่สุดก็มีตัวเลขยาว 1 ถึง 6 หลัก ตัวอย่างเช่นอาจมี 50,000 แถวที่ขึ้นต้นด้วย 'ABCD_BGX1741F_2006_13_20110808.xml @' และตามด้วยตัวเลขที่แตกต่างกัน 50,000 ตัวเลข

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

เป็นการทดสอบฉันทำซ้ำตาราง (ใน schema + tablespace เดียวกัน) กับ DDL เดียวกันและเนื้อหาเดียวกันแน่นอน ฉันสร้างดัชนีที่ไม่ซ้ำกันขึ้นใหม่ในตารางแรกเพื่อทำการวัดที่ดีและสร้างดัชนีเดียวกันที่แน่นอนบนตารางโคลน DBMS_STATS.GATHER_SCHEMA_STATS('schemaname',estimate_percent=>100,cascade=>true);ผม คุณสามารถเห็นได้ว่าชื่อดัชนีนั้นต่อเนื่องกัน ดังนั้นตอนนี้ความแตกต่างเพียงอย่างเดียวระหว่างสองตารางคือการโหลดครั้งแรกตามลำดับแบบสุ่มเป็นระยะเวลานานโดยมีบล็อกกระจายอยู่บนดิสก์ (ในพื้นที่ตารางพร้อมกับตารางขนาดใหญ่อื่น ๆ ) ที่สองถูกโหลดเป็นแบตช์เดียว INSERT เลือก นอกจากนั้นฉันไม่สามารถจินตนาการถึงความแตกต่างได้ (ตารางต้นฉบับถูกย่อขนาดตั้งแต่การลบครั้งใหญ่ครั้งล่าสุดและไม่มีการลบครั้งเดียวหลังจากนั้น)

ต่อไปนี้เป็นแผนคิวรีสำหรับตารางป่วยและโคลน (สตริงภายใต้แปรงสีดำเหมือนกันทั่วรูปภาพและภายใต้แปรงสีเทา)

แผนแบบสอบถาม

(ในตัวอย่างนี้มีแถว 1867 แถวที่ขึ้นต้นด้วยตัวระบุที่เป็นสีดำแปรงแบบสอบถามแบบ 2 แถวจะสร้างความเป็นหัวใจของ 1867 * 2 แบบสอบถามแบบ 3 แถวจะสร้างความเป็นหัวใจที่ 1867 * 3 เป็นต้นไม่สามารถ เป็นเรื่องบังเอิญ Oracle ดูเหมือนจะไม่สนใจจุดสิ้นสุดของตัวระบุ)

สิ่งที่อาจทำให้เกิดพฤติกรรมนี้ เห็นได้ชัดว่ามันค่อนข้างแพงในการสร้างตารางขึ้นมาใหม่

USER_TABLES: http://i.stack.imgur.com/nDWze.jpg USER_INDEXES: http://i.stack.imgur.com/DG9um.jpgฉันเปลี่ยนชื่อสกีมาและพื้นที่ตารางเท่านั้น คุณจะเห็นว่าชื่อตารางและดัชนีนั้นเหมือนกับในภาพหน้าจอของแผนแบบสอบถาม

คำตอบ:


7

(นี่เป็นการตอบคำถามอื่น ๆ เกี่ยวกับสาเหตุที่ฮิสโทแกรมแตกต่างกัน)

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

ตามคู่มือการปรับแต่งประสิทธิภาพ :

เมื่อคุณวางตารางข้อมูลเวิร์กโหลดที่ใช้โดยคุณลักษณะการรวบรวมฮิสโตแกรมอัตโนมัติและประวัติสถิติที่บันทึกไว้ซึ่งใช้โดยโพรซีเดอร์ RESTORE _ * _ STATS จะหายไป หากไม่มีข้อมูลนี้คุณสมบัติเหล่านี้จะทำงานไม่ถูกต้อง

ตัวอย่างเช่นนี่คือตารางที่มีข้อมูลเอียง แต่ไม่มีฮิสโตแกรม:

drop table test1;
create table test1(a date);
insert into test1 select date '2000-01-01'+level from dual connect by level <= 10;
insert into test1 select date '2000-01-01' from dual connect by level <= 1000;
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
select histogram from user_tab_columns where table_name = 'TEST1';

HISTOGRAM
---------
NONE

เรียกใช้สิ่งเดียวกัน แต่เมื่อมีแบบสอบถามก่อนรวบรวมสถิติจะสร้างฮิสโตแกรม

drop table test1;
create table test1(a date);
insert into test1 select date '2000-01-01'+level from dual connect by level <= 10;
insert into test1 select date '2000-01-01' from dual connect by level <= 1000;
select count(*) from test1 where a = sysdate; --Only new line
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/
select histogram from user_tab_columns where table_name = 'TEST1';

HISTOGRAM
---------
FREQUENCY

2
ตัวอย่างง่ายๆที่ยอดเยี่ยม คุณมีความคิดใด ๆ ว่าเหตุใด CBO จึงใช้ฮิสโตแกรมสำหรับการประเมินภาวะเชิงการนับในการสแกนที่เป็นเอกลักษณ์มากกว่าแค่การสมมติ 1
แจ็คดักลาส

ขอบคุณ! ฉันทำซ้ำกับชนิดของข้อมูลและแบบสอบถามในบล็อกของฉัน: joco.name/2014/01/05/ …
fejesjoco

@ แจ็คฉันคิดว่ามันเป็นความเกียจคร้าน วิศวกรของออราเคิลต้องเข้าใจว่าสถิติของดัชนีที่ไม่ซ้ำกันนั้นจะมีจำนวนค่าที่แตกต่างกันเป็นแถวดังนั้นสมมติฐานที่ 1 เกี่ยวกับ cardinality นั้นไม่ได้รับการเดินสาย แต่ใช้จากสถิติเช่นเดียวกับกรณีอื่น ๆ นอกจากนี้ในกรณีทั่วไปฮิสโทแกรมมีการรวบรวมสถิติอย่างง่าย เคสของฉันดูเหมือนจะพิเศษมากเพราะมีปุ่มยาวเท่านั้น แต่ฉันเชื่อว่ามันใช้งานได้ดี
fejesjoco

@fejesjoco ฉันคิดว่าคำอธิบายของ JL น่าจะเป็นไปได้มากกว่าเพราะฮิสโทแกรมจะทำให้สถิติทั่วไปในกรณีที่ค้นหาแบบครั้งเดียว (โดยไม่มีin) ใช่ไหม? ฉันคิดว่า CBO ทำข้อสันนิษฐานว่ามีความสำคัญ 1 แต่ในกรณีที่ง่ายที่สุดเท่านั้น ฉันคิดว่าคุณสามารถUNION ALLหลีกเลี่ยงปัญหาทั้งหมดได้ด้วยการใช้งานที่ยิ่งใหญ่แต่อาจมีสาเหตุอื่นที่ไม่ควรทำเช่นนั้นและ JL ก็กล่าวถึงวิธีแก้ไขปัญหาอื่น ๆ ที่เป็นไปได้ในโพสต์บล็อกที่เชื่อมโยง
แจ็คดักลาส

1
ความลึกลับอีกข้อหนึ่งที่ควรพิจารณา - ฮิสโตแกรมนี้สร้างขึ้นตั้งแต่แรกอย่างไร Oracle ดูเหมือนจะพิจารณาคอลัมน์ที่จะเบ้หากมีการซ้ำซ้อนซึ่งแน่นอนว่าคอลัมน์ที่ไม่ซ้ำกันของคุณจะไม่มี มีใครจงใจสร้าง histogram นี้ (น่า) หรือคนที่ไม่รวบรวมสถิติกับที่ไม่ได้แนะนำmethod_opt=>'for all indexed columns'?
Jon Heller

8

ฉันพบวิธีแก้ปัญหา! มันสวยมากและฉันได้เรียนรู้มากมายเกี่ยวกับออราเคิล

ในหนึ่งคำ: ฮิสโทแกรม

ฉันเริ่มอ่านมากเกี่ยวกับวิธีการทำงานของ CBO ของออราเคิลและฉันสะดุดฮิสโตแกรม ฉันไม่เข้าใจดังนั้นฉันจึงดูที่ตาราง USER_HISTOGRAMS และvoilá มีหลายแถวสำหรับตารางป่วยและไม่มีอะไรจริงสำหรับตารางโคลน สำหรับตารางป่วยมีหนึ่งแถวสำหรับแต่ละส่วนเริ่มต้นที่แตกต่างกัน 8 ตัว และนี่คือกุญแจ: พวกมันถูกตัดที่ 32 ตัวอักษรก่อนเครื่องหมาย @ ดังที่ฉันได้กล่าวไปแล้วว่าส่วนแรกของคีย์นั้นมีความซ้ำซ้อนสูงพวกมันต่างจากเครื่องหมาย @

ดูเหมือนว่าฮิสโทแกรมจะมีประสิทธิภาพมากกว่าความจริงง่ายๆที่ดัชนีที่ไม่ซ้ำกันจะมีความสำคัญเป็น 0 หรือ 1 ตามค่าที่กำหนด เมื่อฉันกำลังสอบถามแถว 2+, Oracle ดูฮิสโตแกรมมันคิดว่าอาจมีค่านับหมื่นสำหรับตัวระบุเริ่มต้นส่วนนั้นและมันโยน CBO นอกหลักสูตร

ฉันลบฮิสโทแกรมของคอลัมน์นั้นในตารางเก่าและปัญหาหายไป!

อ่านเพิ่มเติม: https://blogs.oracle.com/optimizer/entry/how_do_i_drop_an_existing_histogram_on_a_column_and_stop_the_auto_stats_gathering_job_from_creating


2
ฉันพูดถึงว่าในห้องแชทของเรา :) chat.stackexchange.com/transcript/message/12987649#12987649
Philᵀᴹ

ฉันไม่เห็น :) สิ่งเดียวที่แปลกคือทำไมมีฮิสโทแกรมในตารางแรกและไม่ได้อยู่ในโคลนฉันคิดว่า gather_schema_stats อัปเดตทุกอย่างไม่ชัด
fejesjoco

6

ฉันส่งอีเมลถึง Jonathan Lewis เกี่ยวกับเรื่องนี้และได้รับคำตอบที่เป็นประโยชน์มาก:

ความผิดปกติในการคำนวณเป็นผลมาจากข้อ จำกัด ของฮิสโตแกรมที่ขึ้นอยู่กับตัวละครโปรดดู:

http://jonathanlewis.wordpress.com/2010/10/13/frequency-histogram-5/ http://jonathanlewis.wordpress.com/2010/10/19/frequency-histograms-6/

ดูตัวอย่างแบบสอบถามสำหรับรายการ IN ไม่ใช่แถวเดียวดังนั้นการคาดเดาเริ่มต้นของฉันคือเครื่องมือเพิ่มประสิทธิภาพได้ใช้กลยุทธ์ทั่วไปสำหรับการคำนวณการเลือกแบบหลายแถวแทนที่จะมีรหัสกรณีพิเศษสำหรับรหัส รายการในคีย์หลัก ฉันเดาว่าคงไม่ยากเกินไปสำหรับพวกเขาที่จะรับรู้กรณีนี้ แต่นักพัฒนาอาจไม่คิดว่ามันคุ้มค่ากับความพยายาม

ฉันขอแนะนำให้อ่านโพสต์บล็อกที่เขาลิงก์พวกเขาอธิบายรายละเอียดเกี่ยวกับข้อ จำกัด ของฮิสโทแกรมที่คุณใช้งานเช่น:

สรุป : ถ้าคุณมีความยาวและคล้ายกันสตริงในคอลัมน์ที่เป็นตัวเลือกที่ดีสำหรับฮิสโตแกรมความถี่ (เช่นคอลัมน์สถานะที่มีคำอธิบายมาก) คุณจะพบปัญหาหากค่าที่หายากมากนั้นดูเหมือนว่าเป็นที่นิยมมาก ค่าสูงสุด 32 อักขระแรก คุณอาจพบว่าทางออกเดียวคือการเปลี่ยนรายการของค่าทางกฎหมาย (แม้ว่ากลยุทธ์ต่างๆที่เกี่ยวข้องกับคอลัมน์เสมือนหรือดัชนีตามฟังก์ชั่นสามารถข้ามปัญหา)


ฮิสโทแกรมเศร้าน่าจะเป็นคุณสมบัติที่รู้จักกันน้อยฉันเดาว่ามันเป็นเพราะมันลึกเกินไปสำหรับนักพัฒนา SQL และส่วนใหญ่เวลาที่พวกเขาทำงาน แต่มันก็ดีที่จะรู้ว่ามีทรัพยากรมากมายเกี่ยวกับมันฉันแค่ไม่ได้มอง สถานที่ที่เหมาะสม :) เป็นเรื่องที่ไม่ดีนักที่ Oracle ลดลงเหลือ 32 ไบต์และทำการตัดสินใจอย่างหายนะ โชคดีที่ฉันไม่ต้องการการปรับแต่งใด ๆ การปล่อยฮิสโทแกรมเป็นการแก้ปัญหาที่สมบูรณ์แบบ ค่าคีย์มีค่าไม่ซ้ำกันฉันมักจะมองหาค่า 20 ค่าในแต่ละครั้งมันทำงานได้ดีกับดัชนีเท่านั้นและเป็นค่าที่กำหนดได้ แต่ฉันจะไม่ใช้ปุ่มยาวในครั้งต่อไปซึ่งแน่นอน
fejesjoco

ฮิสโทแกรมเป็นที่รู้จักกันดีในกลุ่ม DBA;) ฉันชอบความจริงที่ว่าคุณดูเหมือนกระตือรือร้นที่จะเรียนรู้สิ่งที่ลึกซึ้งยิ่งขึ้นและคิดว่าคุณควรอ่านหนังสือของ JLเป็นอย่างดี โดยทั่วไปแล้ว CBO ทำได้ดีมาก: จะมีคดีที่ต้องตรวจสอบอยู่เสมอ แต่มันก็คุ้มค่าที่ระลึกไว้เสมอว่าแม้จะไม่มีการตัดออก แต่การประมาณการก็เป็นเพียงการประมาณการเสมอ
แจ็คดักลาส

1
หากคุณเรียกใช้งานสถิติปกติ (เช่นเดียวกับที่Oracle ดำเนินการตามค่าเริ่มต้นในการติดตั้งใหม่ทั้งหมด) คุณอาจพบว่าฮิสโทแกรมปรากฏขึ้นอีกครั้งคุณอาจจำเป็นต้องหาวิธีป้องกัน (เช่นLOCK_TABLE_STATS )
Jack Douglas

ฉันพูดถึงบล็อกโพสต์ในคำตอบของฉันมีคำแนะนำเกี่ยวกับวิธีการป้องกันฮิสโตแกรมสำหรับคอลัมน์
fejesjoco

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