क्या मैं दो तालिकाओं पर एक सारगर्भित पहला अक्षर मिलान कर सकता हूँ?


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

एस क्यू एल सर्वर। क्या इस SARGable को बनाने / तेज़ चलाने का कोई तरीका है? मैं व्यक्तियों की मेज पर कॉलम नहीं बना सकता, लेकिन मैं व्यक्तियों 2 पर कॉलम बना सकता हूं।


3
आप जानते हैं कि वास्तव में उस क्वेरी का परिणाम एक प्रकार का क्रोस जॉइन होने वाला है?
ypercube y

1
टेबल कितनी बड़ी हैं? यदि वे प्रत्येक को मात्र 10K पंक्तियाँ कहते हैं, तो परिणाम कम से कम 4 मिलियन पंक्तियों का होगा। मुझे आश्चर्य है कि ऐसी क्वेरी का उपयोग क्या होगा।
ypercube y

1
@ ypercube y शायद फजी मैचिंग का उपयोग करके कुछ डिडुप्लीकेशन प्रक्रिया में एक प्रारंभिक इनपुट है?
मार्टिन स्मिथ

एक बुरे विचार की तरह लगता है। आप यहां क्या हासिल करने की कोशिश कर रहे हैं?
डेविड ovו Davidו मार्कोविट्ज़

यह सिर्फ उदाहरण के लिए था। अधिक विधेय हैं। मार्टिन स्मिथ के पास सही विचार है, यह समर्पण के लिए है।
अंतिमचैनसी

जवाबों:


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;

और परिणाम:

+ ---------- + ----------- + ---------- + --------------- - + ---------- + ----------- + ---------- + ------------- ---- +
| व्यक्ति | फर्स्टनाम | अंतिम नाम | LastNameInitial | व्यक्ति | फर्स्टनाम | अंतिम नाम | LastNameInitial |
+ ---------- + ----------- + ---------- + --------------- - + ---------- + ----------- + ---------- + ------------- ---- +
| 2 | जो | काला | B | 2 | जो | काला | B |
| 1 | मैक्स | वर्नोन | वी | 1 | मैक्स | वर्नोन | वी |
+ ---------- + ----------- + ---------- + --------------- - + ---------- + ----------- + ---------- + ------------- ---- +

निष्पादन योजना, प्रति तालिका केवल दो पंक्तियों के साथ (बेशक बहुत पंक्तियाँ नहीं हैं!)

यहां छवि विवरण दर्ज करें


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 y

@ ypercube y अगर इंडेक्स i.stack.imgur.com/RSzcT.png को कवर कर रहा है तो यह इस तरह की योजना दे सकता है । हालांकि मुझे अपने उत्तर में योजना पर कोई लाभ नहीं दिखाई दे रहा है। के रूप में यह अभी भी बाहरी तालिका में सभी पंक्तियों को पढ़ने की जरूरत खत्म हो जाएगा, बस अब एक स्कैन के बजाय 26 के माध्यम से चाहता है।
मार्टिन स्मिथ

2

मैं 3,423 पंक्तियों और 195 विशिष्ट मूल्यों के साथ एक तालिका है Name। मैं इस तालिका P(व्यक्ति) को कॉल करूंगा और इसे P2(person2) बनाने के लिए डुप्लिकेट करूंगा। पूर्णांक ID स्तंभ पर एक अद्वितीय, संकुल प्राथमिक कुंजी है। मैं Microsoft SQL Server 2016 (KB3194716) डेवलपर संस्करण (64-बिट) का उपयोग विंडोज 10 प्रो 6.3 पर 32 जीबी रैम के साथ कर रहा हूं।

आधार क्वेरी के साथ

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

मुझे 3200-3300ms (आँकड़ों में io से) में 1.5M पंक्तियाँ मिलीं।

यहां छवि विवरण दर्ज करें

इस प्रकार पुनः लिखने से -

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

बीता 50-60 सेमी तक कम हो जाता है और योजना है:

यहां छवि विवरण दर्ज करें

मिलान एल्गोरिथ्म के कारण कम पंक्तियाँ (3,423) वापस आ जाती हैं। आधार क्वेरी को बदलकर एक ही योजना और पंक्ति गणना प्राप्त की जाती है select distinct

अनुक्रमित, कंप्यूटेड कॉलम बनाकर

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

create index ix1 on dbo.p2(Name1);

बीता हुआ समय 45-50ms तक गिर जाता है।

यहां छवि विवरण दर्ज करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.