ฉันสังเกตเห็นว่าเมื่อมีการรั่วไหลของเหตุการณ์ tempdb (ทำให้เกิดการสืบค้นที่ช้า) ซึ่งบ่อยครั้งที่การประมาณแถวนั้นเป็นวิธีการปิดการเข้าร่วมแบบเฉพาะ ฉันเคยเห็นเหตุการณ์การรั่วไหลเกิดขึ้นจากการรวมและแฮชรวมและพวกเขามักจะเพิ่มรันไทม์ 3x เป็น 10x คำถามนี้เกี่ยวข้องกับวิธีปรับปรุงการประมาณการแถวภายใต้สมมติฐานว่าจะลดโอกาสการเกิดเหตุการณ์หก
จำนวนแถวจริง 40k
สำหรับแบบสอบถามนี้แผนจะแสดงค่าประมาณแถวที่ไม่ดี (11.3 แถว):
select Value
from Oav.ValueArray
where ObjectId = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
สำหรับแบบสอบถามนี้แผนแสดงการประมาณแถวที่ดี (56k แถว):
declare @a bigint = (select convert(bigint, Value) NodeId
from Oav.ValueArray
where PropertyId = 3331
and ObjectId = 3540233
and Sequence = 2);
select Value
from Oav.ValueArray
where ObjectId = @a
and PropertyId = 2840
option (recompile);
สามารถเพิ่มสถิติหรือคำแนะนำเพื่อปรับปรุงการประมาณแถวสำหรับกรณีแรกได้หรือไม่ ฉันพยายามเพิ่มสถิติด้วยค่าตัวกรองเฉพาะ (คุณสมบัติ = 2840) แต่อาจไม่ได้รับชุดค่าผสมที่ถูกต้องหรืออาจจะถูกละเว้นเพราะ ObjectId ไม่เป็นที่รู้จักในเวลารวบรวมและอาจเลือกค่าเฉลี่ยมากกว่า ObjectIds ทั้งหมด
มีโหมดใดบ้างที่จะทำแบบสอบถามโพรบก่อนจากนั้นใช้โหมดนั้นเพื่อกำหนดการประมาณแถวหรือต้องบินสุ่มสี่สุ่มห้า?
คุณสมบัติเฉพาะนี้มีค่ามากมาย (40k) บนวัตถุบางส่วนและเป็นศูนย์ในส่วนใหญ่ ฉันจะมีความสุขกับคำใบ้ที่สามารถระบุจำนวนแถวสูงสุดสำหรับการเข้าร่วมที่กำหนดได้ นี่เป็นปัญหาที่มักเกิดขึ้นเนื่องจากบางพารามิเตอร์อาจถูกกำหนดแบบไดนามิกเป็นส่วนหนึ่งของการเข้าร่วมหรือน่าจะอยู่ในมุมมองที่ดีกว่า (ไม่รองรับตัวแปร)
มีพารามิเตอร์ใดบ้างที่สามารถปรับเพื่อลดโอกาสการรั่วไหลของเทมป์ให้เหลือน้อยที่สุด (เช่นหน่วยความจำขั้นต่ำต่อการค้นหา)? แผนแข็งแกร่งไม่มีผลต่อประมาณการ
แก้ไข 2013/11/05 : การตอบสนองต่อความคิดเห็นและข้อมูลเพิ่มเติม:
นี่คือภาพแผนแบบสอบถาม คำเตือนเกี่ยวกับ cardinality / ค้นหาภาคที่มีการแปลง ():
ต่อความคิดเห็นของ @Aaron Bertrand ฉันลองแทนที่การแปลง () เป็นแบบทดสอบ:
create table Oav.SeekObject (
LookupId bigint not null primary key,
ObjectId bigint not null
);
insert into Oav.SeekObject (
LookupId, ObjectId
) VALUES (
1, 3540233
)
select Value
from Oav.ValueArray
where ObjectId = (select ObjectId
from Oav.SeekObject
where LookupId = 1)
and PropertyId = 2840
option (recompile);
ในฐานะที่เป็นจุดสนใจที่แปลก แต่ประสบความสำเร็จก็อนุญาตให้มันทำการลัดวงจรการค้นหา:
select Value
from Oav.ValueArray
where ObjectId = (select ObjectId
from Oav.ValueArray
where PropertyId = 2840
and ObjectId = 3540233
and Sequence = 2)
and PropertyId = 2840
option (recompile);
ทั้งสองรายการมีการค้นหาคีย์ที่เหมาะสม แต่มีเพียงรายการแรกเท่านั้นที่แสดงรายการ "เอาต์พุต" ของ ObjectId ฉันเดาว่าสิ่งที่สองคือการลัดวงจรจริง ๆ ?
มีใครสามารถตรวจสอบได้ว่ามีการตรวจพร็อดแถวเดียวเพื่อช่วยในการประมาณแถวหรือไม่ ดูเหมือนว่าผิดที่จะ จำกัด การปรับให้เหมาะสมกับการประมาณค่าฮิสโตแกรมเท่านั้นเมื่อการค้นหา PK แบบแถวเดียวสามารถปรับปรุงความถูกต้องของการค้นหาในฮิสโตแกรมได้อย่างมาก (โดยเฉพาะอย่างยิ่งหากมีการรั่วไหล เมื่อมี 10 ของการรวมย่อยเหล่านี้ในแบบสอบถามจริงพวกเขาจะเกิดขึ้นในแบบคู่ขนาน
หมายเหตุด้านข้างเนื่องจาก sql_variant จัดเก็บประเภทฐาน (SQL_VARIANT_PROPERTY = BaseType) ภายในเขตข้อมูลตัวเองฉันคาดว่าการแปลง () จะเกือบจะไร้ค่าตราบใดที่มันแปลงได้ "โดยตรง" (เช่นไม่ใช่สตริงถึงทศนิยม หรืออาจเป็น int ถึง bigint) เนื่องจากไม่เป็นที่รู้จักในเวลารวบรวม แต่อาจเป็นที่รู้จักของผู้ใช้บางทีฟังก์ชัน "AssumeType (type, ... )" สำหรับ sql_variants จะช่วยให้พวกเขาได้รับการปฏิบัติที่โปร่งใสมากขึ้น
declare @a bigint =
อย่างที่คุณทำดูเหมือนเป็นวิธีแก้ปัญหาที่เป็นธรรมชาติสำหรับฉันทำไมจึงไม่ยอมรับ?
CONVERT()
ในคอลัมน์แล้วเข้าร่วม นี่คือกรณีส่วนใหญ่ไม่ได้มีประสิทธิภาพอย่างแน่นอน ในค่าเฉพาะนี้มีเพียงค่าเดียวที่จะถูกแปลงค่าซึ่งอาจไม่ใช่ปัญหา แต่ดัชนีใดที่คุณมีอยู่ในตาราง การออกแบบ EAV มักจะทำงานได้ดีโดยมีการจัดทำดัชนีที่เหมาะสมเท่านั้น (ซึ่งหมายถึงดัชนีจำนวนมากในตารางแคบ ๆ )