ฉันสามารถจับคู่จดหมายตัวแรกที่สามารถอ้างอิงได้ในสองตารางได้หรือไม่?


9
select value 
from persons p join persons2 p2 
    on left(p.lastname,1) = left(p2.lastname,1)

เซิร์ฟเวอร์ SQL มีวิธีใดที่ทำให้ SARGable นี้ / ทำงานได้เร็วขึ้น? ฉันไม่สามารถสร้างคอลัมน์ในตารางบุคคล แต่ฉันสามารถสร้างคอลัมน์ใน person2


3
คุณรู้หรือไม่ว่าผลลัพธ์ของการสืบค้นนั้นจะเป็นประเภท CROSS JOIN
ypercubeᵀᴹ

1
โต๊ะใหญ่แค่ไหน? หากพวกเขาแต่ละคนบอกว่าแถว 10K เพียงอย่างเดียวผลจะมีอย่างน้อย 4 ล้านแถว ฉันสงสัยว่าการใช้ข้อความค้นหานั้นจะเป็นอย่างไร
ypercubeᵀᴹ

1
@ ypercubeᵀᴹอาจเป็นอินพุตเริ่มต้นในกระบวนการคัดลอกซ้ำโดยใช้การจับคู่แบบคลุมเครือหรือไม่
Martin Smith

ฟังดูเหมือนเป็นไอเดียที่ไม่ดี คุณพยายามทำอะไรที่นี่
เดวิดדודו Markovitz

นี่เป็นเพียงตัวอย่าง มีภาคแสดงมากขึ้น มาร์ตินสมิ ธ มีความคิดที่ถูกต้องมันมีไว้เพื่อขจัดข้อมูลซ้ำซ้อน
lastchancexi

คำตอบ:


9

สร้างมุมมองบนตารางที่มีคอลัมน์ที่คำนวณแล้วซึ่งถูกกำหนดเป็นLEFT(lastname, 1)ของแต่ละตารางจากนั้นเปรียบเทียบค่าคอลัมน์ที่คำนวณแล้ว

นี่คือเตียงทดสอบที่แสดงวิธีการทำ:

CREATE TABLE dbo.Persons
(
    PersonID int NOT NULL
        CONSTRAINT PK_Persons
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , FirstName nvarchar(500) NOT NULL
    , LastName nvarchar(500) NOT NULL
);

CREATE TABLE dbo.Persons2
(
    PersonID int NOT NULL
        CONSTRAINT PK_Persons2
        PRIMARY KEY CLUSTERED
        IDENTITY(1,1)
    , FirstName nvarchar(500) NOT NULL
    , LastName nvarchar(500) NOT NULL
);

GO
CREATE VIEW dbo.PersonsView
WITH SCHEMABINDING
AS
SELECT p1.PersonID
    , p1.FirstName
    , p1.LastName 
    , LastNameInitial = LEFT(p1.LastName, 1)
FROM dbo.Persons p1;
GO
CREATE VIEW dbo.PersonsView2
WITH SCHEMABINDING
AS
SELECT p2.PersonID
    , p2.FirstName
    , p2.LastName 
    , LastNameInitial = LEFT(p2.LastName, 1)
FROM dbo.Persons p2;
GO
CREATE UNIQUE CLUSTERED INDEX CX_PersonsView
ON dbo.PersonsView(PersonID);
CREATE NONCLUSTERED INDEX IX_PersonsView_LastNameInitial
ON dbo.PersonsView(LastNameInitial)
INCLUDE (FirstName, LastName);

CREATE UNIQUE CLUSTERED INDEX CX_PersonsView2
ON dbo.PersonsView2(PersonID);
CREATE NONCLUSTERED INDEX IX_PersonsView2_LastNameInitial
ON dbo.PersonsView2(LastNameInitial)
INCLUDE (FirstName, LastName);

CREATE STATISTICS ST_PersonsView_001
ON dbo.PersonsView(LastName);

CREATE STATISTICS ST_PersonsView2_001
ON dbo.PersonsView2(LastName);

ที่นี่เราจะแทรกข้อมูลตัวอย่าง:

INSERT INTO dbo.Persons(FirstName, LastName)
VALUES ('Max', 'Vernon')
    , ('Joe', 'Black');

INSERT INTO dbo.Persons2(FirstName, LastName)
VALUES ('Max', 'Vernon')
    , ('Joe', 'Black');

นี่คือSELECTแบบสอบถาม:

SELECT *
FROM dbo.PersonsView pv1
    INNER JOIN dbo.PersonsView2 pv2 ON pv1.LastNameInitial = pv2.LastNameInitial;

และผลลัพธ์:

+ + ----------- ---------- ---------- + + --------------- - + + ----------- ---------- ---------- + + ------------- ---- +
| PersonID | ชื่อ นามสกุล | LastNameInitial | PersonID | ชื่อ นามสกุล | LastNameInitial |
+ + ----------- ---------- ---------- + + --------------- - + + ----------- ---------- ---------- + + ------------- ---- +
| 2 | โจ | ดำ | B | 2 | โจ | ดำ | B |
| 1 | สูงสุด | เวอร์นอน | V | 1 | สูงสุด | เวอร์นอน | V |
+ + ----------- ---------- ---------- + + --------------- - + + ----------- ---------- ---------- + + ------------- ---- +

แผนการดำเนินการโดยมีเพียงสองแถวต่อตาราง (ยอมรับกันไม่มากนัก!)

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


11

หากlastnameมีการจัดทำดัชนีคอลัมน์ในตารางอย่างน้อยหนึ่งตารางคุณก็สามารถใช้LIKE

SELECT *
FROM   persons p
       INNER JOIN persons2 p2
               ON p2.lastname LIKE LEFT(p.lastname, 1) + '%' 

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

แผนนี้สามารถค้นหาบนโต๊ะที่ระบุไว้ทางด้านซ้ายของสิ่งที่คล้ายกัน

เช่นON p.lastname LIKE LEFT(p2.lastname, 1) + '%'จะไม่สามารถใช้ประโยชน์จากดัชนีpersons2ที่ใช้ด้านบน แต่สามารถค้นหาpersonsได้

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


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

@ ypercubeᵀᴹมันจะให้แผนเช่นนี้ถ้าดัชนีจะครอบคลุมi.stack.imgur.com/RSzcT.png ฉันไม่เห็นความได้เปรียบใด ๆ เหนือแผนในคำตอบของฉัน ในขณะที่มันยังคงต้องอ่านแถวทั้งหมดในตารางด้านนอกตอนนี้ผ่าน 26 ค้นหามากกว่าหนึ่งสแกน
Martin Smith

2

ฉันเกิดขึ้นจะมีตารางที่มี 3,423 แถวและ 195 Nameค่าแตกต่างกันใน ฉันจะเรียกตารางนี้P(คน) และทำซ้ำเพื่อสร้างP2(person2) มีคีย์หลักที่ไม่ซ้ำกันและคลัสเตอร์ในคอลัมน์ ID จำนวนเต็ม ฉันใช้ Microsoft SQL Server 2016 (KB3194716) Developer Edition (64 บิต) บน Windows 10 Pro 6.3 พร้อม 32GB RAM

ด้วยแบบสอบถามฐาน

select
    p.pid
from dbo.p
inner join dbo.p2 
    on LEFT(p.name, 1) = LEFT(p2.name, 1);

ฉันได้รับแถว 1.5M ที่ส่งคืนใน 3200-3300ms (จากสถิติ io)

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

โดยการเขียนใหม่จึง -

select
    p.pid
from dbo.p
where exists
(
    select 1
    from dbo.p2 
    where LEFT(p.name, 1) = LEFT(p2.name, 1)
);

ผ่านไปลด 50-60ms และแผนคือ:

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

ส่งคืนแถวที่น้อยลง (3,423) เนื่องจากอัลกอริทึมที่ตรงกัน select distinctวางแผนและแถวเดียวกันนับจะทำได้โดยการเปลี่ยนแบบสอบถามฐาน

โดยการสร้างคอลัมน์ที่คำนวณและจัดทำดัชนี

alter table dbo.p2
add Name1 as Left(Name, 1);

create index ix1 on dbo.p2(Name1);

เวลาที่ผ่านไปลดลงถึง 45-50ms

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

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