คีย์หลักคอมโพสิตในฐานข้อมูล SQL Server แบบหลายผู้เช่า


16

ฉันกำลังสร้างแอพหลายผู้เช่า (ฐานข้อมูลเดียวสกีมาเดียว) โดยใช้ ASP Web API, Entity Framework และฐานข้อมูล SQL Server / Azure แอปนี้จะใช้งานโดยลูกค้า 1,000-5,000 คน ตารางทั้งหมดจะมีฟิลด์TenantId(Guid / UNIQUEIDENTIFIER) ตอนนี้ฉันใช้คีย์หลักของฟิลด์เดียวซึ่งเป็นรหัส (Guid) แต่ด้วยการใช้เพียงแค่รหัสเขตข้อมูลฉันต้องตรวจสอบว่าข้อมูลที่ให้โดยผู้ใช้นั้นมาจาก / สำหรับผู้เช่าที่เหมาะสมหรือไม่ ตัวอย่างเช่นฉันมีSalesOrderตารางที่มีCustomerIdเขตข้อมูล ทุกครั้งที่ผู้ใช้โพสต์ / อัปเดตคำสั่งขายฉันต้องตรวจสอบว่าCustomerIdมาจากผู้เช่ารายเดียวกันหรือไม่ แย่ลงเพราะผู้เช่าแต่ละรายอาจมีหลายสาขา แล้วฉันจะมีการตรวจสอบและTenantId OutletIdมันเป็นฝันร้ายของการบำรุงรักษาและไม่ดีต่อประสิทธิภาพ

ฉันคิดว่าจะเพิ่มไปยังคีย์หลักพร้อมกับTenantId Idและอาจเพิ่มOutletIdด้วย ดังนั้นหลักสำคัญในSalesOrderตารางจะเป็น: Id, และTenantId OutletIdข้อเสียของวิธีการนี้คืออะไร? ประสิทธิภาพจะเจ็บอย่างรุนแรงโดยใช้คีย์ผสมหรือไม่ คีย์ใบสั่งผสมมีความสำคัญหรือไม่ มีวิธีแก้ปัญหาที่ดีกว่าสำหรับฉันหรือไม่?

คำตอบ:


34

การทำงานบนระบบหลายผู้เช่าขนาดใหญ่ (วิธีการรวมกับลูกค้ากระจายไปทั่วเซิร์ฟเวอร์ 18+ แต่ละเซิร์ฟเวอร์มีสคีมาเหมือนกันเพียงลูกค้าที่แตกต่างกันและธุรกรรมหลายพันต่อวินาทีต่อเซิร์ฟเวอร์ต่อวินาที) ฉันสามารถพูดได้:

  1. มีบางคน (อย่างน้อยอย่างน้อย) ที่จะเห็นด้วยกับการเลือก GUID ของคุณเป็น ID สำหรับทั้ง "TenantID" และเอนทิตี "ID" ใด ๆ แต่ไม่ใช่ไม่ใช่ทางเลือกที่ดี ข้อพิจารณาอื่น ๆ ทั้งหมด, ตัวเลือกนั้นเพียงอย่างเดียวจะได้รับผลกระทบในสองสามประการ: การแตกแฟรกเมนต์เพื่อเริ่มต้น, พื้นที่ที่สูญเปล่าจำนวนมาก (อย่าพูดว่าดิสก์ราคาถูกเมื่อคิดถึงการจัดเก็บข้อมูลองค์กร - SAN - หรือแบบสอบถามใช้เวลานานขึ้น การถือครองแถวน้อยกว่าที่ทำได้ด้วยINTหรือBIGINTแม้แต่) การสนับสนุนและการบำรุงรักษาที่ยากขึ้น ฯลฯ GUID นั้นยอดเยี่ยมสำหรับการพกพา ข้อมูลถูกสร้างขึ้นในบางระบบและโอนไปยังระบบอื่นหรือไม่? ถ้าไม่เช่นนั้นเปลี่ยนไปชนิดขนาดกะทัดรัดมากขึ้นข้อมูล (เช่นTINYINT, SMALLINT, INTหรือแม้กระทั่งBIGINT) และเพิ่มขึ้นตามลำดับผ่านIDENTITYหรือSEQUENCE.

  2. ด้วยรายการที่ 1 คุณไม่จำเป็นต้องมีฟิลด์ TenantID ในทุก ๆ ตารางที่มีข้อมูลผู้ใช้ ด้วยวิธีนี้คุณสามารถกรองสิ่งใดก็ได้โดยไม่จำเป็นต้องมีการเพิ่มเข้าร่วม นอกจากนี้ยังหมายความว่าแบบสอบถามทั้งหมดสำหรับตารางข้อมูลลูกค้าจำเป็นต้องมีเงื่อนไขTenantIDในการเข้าร่วมและ / หรือ WHERE clause สิ่งนี้ยังช่วยรับประกันว่าคุณจะไม่ผสมผสานข้อมูลจากลูกค้าที่แตกต่างกันโดยไม่ตั้งใจหรือแสดงข้อมูลผู้เช่า A จากผู้เช่า B

  3. ฉันคิดว่าจะเพิ่ม TenantId เป็นคีย์หลักพร้อมกับรหัส และอาจเพิ่ม OutletId ด้วย ดังนั้นคีย์หลักในตารางใบสั่งขายจะเป็นรหัส, TenantId, OutletId

    ใช่คุณควรจะมีดัชนีคลัสเตอร์ของคุณบนโต๊ะลูกค้าข้อมูลเป็นคีย์คอมโพสิตรวมTenantIDและ**ID สิ่งนี้ยังช่วยให้มั่นใจได้ว่าTenantIDอยู่ในดัชนี NonClustered ทุกตัว (เนื่องจากมีคีย์ดัชนีแบบคลัสเตอร์) ซึ่งคุณจะต้องมีอยู่ตั้งแต่ 98.45% ของการสอบถามกับตารางลูกค้า - ข้อมูลจะต้องการTenantID(ข้อยกเว้นหลักคือเมื่อขยะเก็บข้อมูลเก่าตาม เปิดCreatedDateและไม่สนใจTenantID)

    ไม่คุณจะไม่รวม FK เช่นOutletIDPK PK ต้องการระบุแถวที่ไม่ซ้ำกันและการเพิ่ม FK จะไม่ช่วยได้ ในความเป็นจริงมันจะเพิ่มโอกาสสำหรับข้อมูลซ้ำสมมติว่า OrderID เป็นเอกลักษณ์สำหรับแต่ละTenantIDเมื่อเทียบกับที่ไม่ซ้ำกันในแต่ละในแต่ละOutletIDTenantID

    นอกจากนี้ไม่จำเป็นต้องเพิ่มOutletIDใน PK เพื่อให้มั่นใจว่า Outlets จากผู้เช่า A ไม่ได้ปะปนกับผู้เช่า B เนื่องจากตารางผู้ใช้ข้อมูลทั้งหมดจะมีTenantIDใน PK นั่นหมายความว่าTenantIDจะอยู่ใน FKs ด้วย . ตัวอย่างเช่นOutletตารางมีค่า PK (TenantID, OutletID)และOrderตารางมีค่า PK (TenantID, OrderID) และ FK (TenantID, OutletID)ซึ่งอ้างอิงค่า PK บนOutletตาราง FK ที่กำหนดไว้อย่างเหมาะสมจะป้องกันข้อมูลของผู้เช่าไม่ให้ถูกผสม

  4. คีย์ใบสั่งผสมมีความสำคัญหรือไม่

    นี่คือที่ที่มันสนุก มีการถกเถียงกันว่าสนามใดควรมาก่อน กฎ "ทั่วไป" สำหรับการออกแบบดัชนีที่ดีคือการเลือกเขตข้อมูลที่เลือกมากที่สุดเพื่อเป็นเขตข้อมูลชั้นนำ TenantIDโดยธรรมชาติแล้วมันจะไม่เป็นสนามที่ถูกเลือกมากที่สุด IDสนามคือสนามเลือกมากที่สุด นี่คือความคิดบางอย่าง:

    • ID แรก:นี่คือฟิลด์ที่เลือกมากที่สุด (เช่นไม่ซ้ำกันมากที่สุด) แต่โดยการเป็นฟิลด์การเพิ่มอัตโนมัติ (หรือสุ่มหากยังคงใช้ GUID) ข้อมูลของลูกค้าแต่ละรายจะถูกกระจายออกไปทั่วแต่ละตาราง ซึ่งหมายความว่ามีบางครั้งที่ลูกค้าต้องการ 100 แถวและต้องมีเกือบ 100 หน้าข้อมูลที่อ่านจากดิสก์ (ไม่เร็ว) ลงใน Buffer Pool (ใช้พื้นที่มากกว่า 10 หน้าข้อมูล) นอกจากนี้ยังเพิ่มความขัดแย้งในหน้าข้อมูลเนื่องจากจะบ่อยขึ้นที่ลูกค้าหลายรายจะต้องปรับปรุงหน้าข้อมูลเดียวกัน

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

    • ผู้เช่ารายแรก:นี่เป็นสิ่งที่ไม่เลือกเลย อาจมีการเปลี่ยนแปลงเล็กน้อยใน 1 ล้านแถวถ้าคุณมีผู้เช่า 100 รายเท่านั้น แต่สถิติของแบบสอบถามเหล่านี้มีความแม่นยำมากขึ้นเนื่องจาก SQL Server จะทราบว่าแบบสอบถามสำหรับผู้เช่า A จะดึงแถว 500,000 แถวกลับมา แต่แบบสอบถามเดียวกันสำหรับผู้เช่า B นั้นมีเพียง 50 แถว นี่คือที่ที่จุดปวดหลักคือ วิธีนี้เพิ่มโอกาสในการมีปัญหาการดมพารามิเตอร์อย่างมากซึ่งการเรียกใช้กระบวนงานที่เก็บไว้ครั้งแรกสำหรับผู้เช่า A และดำเนินการอย่างเหมาะสมโดยใช้ Query Optimizer ที่ดูสถิติเหล่านั้นและรู้ว่าจำเป็นต้องมีแถว 500k ที่มีประสิทธิภาพ แต่เมื่อผู้เช่า B ที่มีเพียง 50 แถวทำงานแผนปฏิบัติการนั้นไม่เหมาะสมอีกต่อไปและในความเป็นจริงแล้วมันไม่เหมาะสมเลยทีเดียว และเนื่องจากข้อมูลไม่ได้ถูกแทรกตามลำดับของฟิลด์นำ

      อย่างไรก็ตามสำหรับ TenantID แรกที่เรียกใช้กระบวนงานที่เก็บไว้ประสิทธิภาพควรดีกว่าในแนวทางอื่นเนื่องจากข้อมูล (อย่างน้อยหลังจากทำการบำรุงรักษาดัชนี) จะถูกจัดระเบียบทางร่างกายและทางตรรกะเพื่อให้หน้าข้อมูลน้อยลงเพื่อตอบสนอง คำสั่ง ซึ่งหมายถึง I / O ทางกายภาพที่น้อยลงการอ่านแบบลอจิคัลที่น้อยลงความขัดแย้งระหว่างผู้เช่าสำหรับหน้าข้อมูลเดียวกันน้อยกว่าพื้นที่ว่างที่เกิดขึ้นในบัฟเฟอร์ Buffer น้อยลง (เช่นปรับปรุงอายุการใช้งานของหน้า) เป็นต้น

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

      ในการรับมือกับปัญหาการสูดดมพารามิเตอร์ที่เพิ่มขึ้นคุณต้องแยกแผนการดำเนินการระหว่างผู้เช่า วิธีการง่าย ๆ คือการใช้WITH RECOMPILEกับ procs หรือOPTION (RECOMPILE)คำใบ้แบบสอบถาม แต่นั่นคือผลการดำเนินงานที่เป็นที่นิยมซึ่งสามารถกำจัดกำไรทั้งหมดที่เกิดขึ้นได้จากการใส่TenantIDครั้งแรก วิธีการที่ผมพบว่าการทำงานที่ดีที่สุดคือการใช้แปร SQL sp_executesqlแบบไดนามิกผ่าน เหตุผลที่ต้องการ Dynamic SQL คือการอนุญาตให้เชื่อมโยง TenantID เข้ากับข้อความของแบบสอบถามในขณะที่เพรดิเคตอื่น ๆ ทั้งหมดที่ปกติจะเป็นพารามิเตอร์จะยังคงเป็นพารามิเตอร์ ตัวอย่างเช่นหากคุณกำลังมองหาคำสั่งซื้อเฉพาะคุณจะทำสิ่งที่ชอบ:

      DECLARE @GetOrderSQL NVARCHAR(MAX);
      SET @GetOrderSQL = N'
        SELECT ord.field1, ord.field2, etc.
        FROM   dbo.Orders ord
        WHERE  ord.TenantID = ' + CONVERT(NVARCHAR(10), @TenantID) + N'
        AND    ord.OrderID = @OrderID_dyn;
      ';
      
      EXEC sp_executesql
         @GetOrderSQL,
         N'@OrderID_dyn INT',
         @OrderID_dyn = @OrderID;
      

      ผลที่ได้นี้คือการสร้างแผนคิวรีที่สามารถใช้ซ้ำได้สำหรับ TenantID นั้นที่จะจับคู่กับปริมาณข้อมูลของผู้เช่ารายนั้น หากผู้เช่ารายเดียวกันนั้นดำเนินการตามขั้นตอนที่เก็บไว้อีกครั้งผู้ใช้ราย@OrderIDนั้นจะใช้แผนคิวรีแคชนั้นซ้ำ ผู้เช่ารายอื่นที่ใช้ขั้นตอนการจัดเก็บเดียวกันนั้นจะสร้างข้อความค้นหาที่แตกต่างกันเฉพาะในมูลค่าของ TenantID แต่ความแตกต่างใด ๆในข้อความค้นหานั้นเพียงพอที่จะสร้างแผนที่แตกต่างกัน และแผนที่สร้างขึ้นสำหรับผู้เช่า B จะไม่เพียง แต่ตรงกับปริมาณข้อมูลสำหรับผู้เช่า B แต่จะสามารถนำมาใช้ซ้ำสำหรับผู้เช่า B สำหรับค่าที่แตกต่างกันของ@OrderID(เนื่องจากภาคแสดงยังคงเป็นพารามิเตอร์)

      ข้อเสียของวิธีนี้คือ:

      • มันเป็นงานเล็ก ๆ น้อย ๆ มากกว่าเพียงแค่พิมพ์ในแบบสอบถามง่าย ๆ (แต่ไม่ใช่แบบสอบถามทั้งหมดจะต้องเป็น SQL แบบไดนามิกเพียงแค่คนที่จบลงด้วยปัญหาการดมกลิ่นพารามิเตอร์)
      • ขึ้นอยู่กับจำนวนผู้เช่าที่อยู่บนระบบมันจะเพิ่มขนาดของแคชแผนเนื่องจากขณะนี้แต่ละแบบสอบถามต้องการ 1 แผนต่อ TenantID ที่กำลังเรียกใช้ นี่อาจไม่ใช่ปัญหา แต่อย่างน้อยสิ่งที่ต้องระวัง
      • Dynamic SQL จะทำลายห่วงโซ่ความเป็นเจ้าของซึ่งหมายความว่าไม่สามารถสันนิษฐานได้ว่าการเข้าถึงแบบอ่าน / เขียนไปยังตารางโดยได้EXECUTEรับอนุญาตใน Stored Procedure การแก้ไขที่ง่าย แต่ปลอดภัยน้อยนั้นเป็นเพียงการให้ผู้ใช้เข้าถึงตารางโดยตรง มันไม่เหมาะอย่างแน่นอน แต่โดยปกติแล้วจะเป็นการแลกเปลี่ยนเพื่อความรวดเร็วและง่ายดาย แนวทางที่ปลอดภัยยิ่งขึ้นคือการใช้ความปลอดภัยที่ใช้ใบรับรอง ความหมายสร้างใบรับรองแล้วสร้างผู้ใช้จากที่รับรองให้สิทธิ์ที่ผู้ใช้สิทธิ์ที่ต้องการ (ผู้ใช้รับรองหรือเข้าสู่ระบบไม่สามารถเชื่อมต่อกับ SQL Server ของตัวเอง) แล้วเข้าสู่ระบบวิธีการจัดเก็บที่ใช้แบบไดนามิก SQL กับที่ รับรองเดียวกันผ่านทางเพิ่มลายเซ็น

        สำหรับข้อมูลเพิ่มเติมเกี่ยวกับโมดูลการเซ็นชื่อและใบรับรองโปรดดูที่: ModuleSigning.Info
         

    โปรดดูหัวข้อUPDATE ที่ส่วนท้ายสำหรับหัวข้อเพิ่มเติมที่เกี่ยวข้องกับปัญหาการจัดการกับการบรรเทาปัญหาสถิติที่เกิดจากการตัดสินใจนี้


** โดยส่วนตัวแล้วฉันไม่ชอบการใช้เพียง "ID" สำหรับชื่อเขตข้อมูล PK ในทุกตารางเนื่องจากไม่มีความหมายและไม่สอดคล้องกันทั่ว FK เนื่องจาก PK เป็น "ID" เสมอและเขตข้อมูลในตารางลูกต้อง รวมชื่อตารางหลัก ตัวอย่างเช่น: ->Orders.ID OrderItems.OrderIDฉันคิดว่ามันง่ายมากที่จะจัดการกับรูปแบบข้อมูลที่มี: ->Orders.OrderID OrderItems.OrderIDสามารถอ่านได้มากขึ้นและลดจำนวนครั้งที่คุณจะได้รับข้อผิดพลาด "การอ้างอิงคอลัมน์ที่ไม่ชัดเจน" :-)


UPDATE

  • จะOPTIMIZE FOR UNKNOWN คำแนะนำการสอบถาม (แนะนำใน SQL Server 2008) ความช่วยเหลือเกี่ยวกับการสั่งซื้อของ PK คอมโพสิตอย่างใดอย่างหนึ่ง?

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

    ตัวเลือกนี้ทำสิ่งเดียวกันกับการคัดลอกพารามิเตอร์อินพุตไปยังตัวแปรโลคัลแล้วใช้ตัวแปรโลคัลในเคียวรี (ฉันทดสอบแล้ว แต่ไม่มีที่ว่างสำหรับที่นี่) ข้อมูลเพิ่มเติมสามารถพบได้ในโพสต์บล็อกนี้: http://www.brentozar.com/archive/2013/06/optimize-for-unknown-sql-server-parameter-sniffing/ จากการอ่านความคิดเห็น Daniel Pepermans ได้ข้อสรุปคล้ายกับของฉันเกี่ยวกับการใช้ Dynamic SQL ที่มีการเปลี่ยนแปลง จำกัด

  • ถ้า ID เป็นฟิลด์นำในดัชนีแบบคลัสเตอร์มันจะช่วย / พอเพียงให้มีดัชนีที่ไม่เป็นคลัสเตอร์บน (TenantID, ID) หรือเพียงแค่ (TenantID) เพื่อให้มีสถิติที่ถูกต้องสำหรับเคียวรีที่ประมวลผลแถวของผู้เช่ารายเดียว

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

    แม้ว่าวิธีนี้จะช่วยแก้ไขปัญหาในทันทีที่สามารถทำแบบสอบถามที่ใช้ TenantID ได้อย่างมีประสิทธิภาพมากขึ้น แต่ก็ยังไม่ได้มีประสิทธิภาพเท่าที่ควรหากเป็นดัชนีแบบคลัสเตอร์ที่อยู่ในลำดับเดียวกัน และตอนนี้เรายังมีอีกหนึ่งดัชนีในทุกตาราง นั่นเพิ่มปริมาณพื้นที่ SAN ที่เราใช้เพิ่มขนาดของการสำรองข้อมูลของเราทำให้การสำรองข้อมูลใช้เวลานานกว่าจะเสร็จสมบูรณ์เพิ่มศักยภาพในการบล็อกและการหยุดชะงักการลดลงของประสิทธิภาพINSERTและDELETEการทำงาน ฯลฯ

    และเรายังคงมีความไร้ประสิทธิภาพโดยทั่วไปของการมีข้อมูลของผู้เช่ากระจายออกไปทั่วหน้าข้อมูลจำนวนมากผสมกับข้อมูลของผู้เช่าอื่น ๆ ดังที่ฉันได้กล่าวไปแล้วการเพิ่มจำนวนของการช่วงชิงบนหน้าเหล่านี้และจะเติมบัฟเฟอร์พูลด้วยหน้าข้อมูลจำนวนมากที่มีแถวที่มีประโยชน์ 1 หรือ 2 แถวโดยเฉพาะอย่างยิ่งเมื่อบางแถวในหน้าเหล่านั้นมีไว้สำหรับลูกค้าที่ ไม่ทำงาน แต่ยังไม่ได้เก็บขยะ มีความเป็นไปได้น้อยกว่ามากสำหรับการใช้หน้าข้อมูลใน Buffer Pool อีกครั้งในวิธีการนี้ดังนั้น Page Life ของเราจึงค่อนข้างต่ำ และนั่นหมายถึงเวลาที่จะกลับไปที่ดิสก์เพื่อโหลดหน้าเว็บมากขึ้น


2
คุณได้พิจารณาหรือทดสอบการปรับให้เหมาะสมที่ไม่รู้จักในพื้นที่ปัญหานี้หรือไม่ แค่สงสัย.
RLF

1
@RLF ใช่เราวิจัยตัวเลือกนั้นแล้วและอย่างน้อยก็ไม่ควรดีกว่าและแย่กว่าประสิทธิภาพที่ดีที่สุดที่เราได้รับจากการมีข้อมูลประจำตัวเป็นอันดับแรก ฉันจำไม่ได้ว่าฉันอ่านตรงไหน แต่ควรให้สถิติ "ค่าเฉลี่ย" แบบเดียวกันกับการกำหนดพารามิเตอร์อินพุตให้กับตัวแปรท้องถิ่นอีกครั้ง แต่บทความนี้อธิบายว่าทำไมตัวเลือกดังกล่าวจึงไม่สามารถแก้ปัญหาได้: brentozar.com/archive/2013/06/ …การอ่านความคิดเห็น Daniel Pepermans มาถึงข้อสรุปที่คล้ายกันอีกครั้ง: Dynamic SQL ที่มีการเปลี่ยนแปลง จำกัด :)
โซโลมอน Rutzky

3
จะเกิดอะไรขึ้นถ้าดัชนีคลัสเตอร์เปิดอยู่(ID, TenantID)และคุณยังสร้างดัชนีที่ไม่ได้ทำคลัสเตอร์(TenantID, ID)หรือเพียงแค่(TenantID)มีสถิติที่ถูกต้องสำหรับแบบสอบถามที่ประมวลผลแถวส่วนใหญ่ของผู้เช่ารายเดียว
Vladimir Baranov

1
@VladimirBaranov คำถามที่ยอดเยี่ยม ฉันได้กล่าวถึงมันในส่วนUPDATEใหม่ในตอนท้ายของคำตอบ :-)
โซโลมอน Rutzky

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