मुझे यह समझने में समस्या है कि SQL सर्वर तालिका में प्रत्येक मूल्य के लिए उपयोगकर्ता परिभाषित फ़ंक्शन को कॉल करने का निर्णय क्यों लेता है, भले ही केवल एक पंक्ति प्राप्त की जानी चाहिए। वास्तविक एसक्यूएल बहुत अधिक जटिल है, लेकिन मैं इस समस्या को कम करने में सक्षम था:
select
S.GROUPCODE,
H.ORDERCATEGORY
from
ORDERLINE L
join ORDERHDR H on H.ORDERID = L.ORDERID
join PRODUCT P on P.PRODUCT = L.PRODUCT
cross apply dbo.GetGroupCode (P.FACTORY) S
where
L.ORDERNUMBER = 'XXX/YYY-123456' and
L.RMPHASE = '0' and
L.ORDERLINE = '01'
इस क्वेरी के लिए, SQL सर्वर उत्पाद तालिका में मौजूद हर एक मान के लिए GetGroupCode फ़ंक्शन को कॉल करने का निर्णय लेता है, भले ही ORDERLINE से लौटी पंक्तियों का अनुमान और वास्तविक संख्या 1 है (यह प्राथमिक कुंजी है):
पंक्ति एक्सप्लोरर को दिखाने वाले प्लान एक्सप्लोरर में एक ही योजना:
टेबल्स:
ORDERLINE: 1.5M rows, primary key: ORDERNUMBER + ORDERLINE + RMPHASE (clustered)
ORDERHDR: 900k rows, primary key: ORDERID (clustered)
PRODUCT: 6655 rows, primary key: PRODUCT (clustered)
स्कैन के लिए उपयोग किया जा रहा सूचकांक है:
create unique nonclustered index PRODUCT_FACTORY on PRODUCT (PRODUCT, FACTORY)
फ़ंक्शन वास्तव में थोड़ा अधिक जटिल है, लेकिन एक ही बात इस तरह से एक डमी मल्टी-स्टेटमेंट फ़ंक्शन के साथ होती है:
create function GetGroupCode (@FACTORY varchar(4))
returns @t table(
TYPE varchar(8),
GROUPCODE varchar(30)
)
as begin
insert into @t (TYPE, GROUPCODE) values ('XX', 'YY')
return
end
मैं शीर्ष 1 उत्पाद लाने के लिए SQL सर्वर को मजबूर करके प्रदर्शन को "ठीक" करने में सक्षम था, हालांकि 1 अधिकतम है जो कभी भी हो सकता है:
select
S.GROUPCODE,
H.ORDERCAT
from
ORDERLINE L
join ORDERHDR H
on H.ORDERID = M.ORDERID
cross apply (select top 1 P.FACTORY from PRODUCT P where P.PRODUCT = L.PRODUCT) P
cross apply dbo.GetGroupCode (P.FACTORY) S
where
L.ORDERNUMBER = 'XXX/YYY-123456' and
L.RMPHASE = '0' and
L.ORDERLINE = '01'
फिर योजना का आकार भी कुछ बदल जाता है जिसकी मुझे उम्मीद थी कि यह मूल रूप से होगा:
हालांकि मैं यह भी कहता हूं कि अनुक्रमणिका PRODUCT_FACTORY क्लस्टर अनुक्रमणिका PRODUCT_PK से छोटी है, लेकिन इसका प्रभाव पड़ेगा, लेकिन यहां तक कि PRODUCT_PK का उपयोग करने के लिए प्रश्न को बाध्य करने के बावजूद, योजना अभी भी मूल है, फ़ंक्शन के लिए 6655 कॉल के साथ।
अगर मैं ORDERHDR को पूरी तरह से छोड़ देता हूं, तो योजना पहले ORDERLINE और PRODUCT के बीच नेस्टेड लूप से शुरू होती है, और फ़ंक्शन को केवल एक बार कहा जाता है।
मैं यह समझना चाहूंगा कि इसका क्या कारण हो सकता है क्योंकि सभी ऑपरेशन प्राथमिक कुंजियों का उपयोग करके किए जाते हैं और इसे कैसे ठीक किया जाए यदि यह अधिक जटिल क्वेरी में होता है जो इसे आसानी से हल नहीं किया जा सकता है।
संपादित करें: तालिका विवरण बनाएं:
CREATE TABLE dbo.ORDERHDR(
ORDERID varchar(8) NOT NULL,
ORDERCATEGORY varchar(2) NULL,
CONSTRAINT ORDERHDR_PK PRIMARY KEY CLUSTERED (ORDERID)
)
CREATE TABLE dbo.ORDERLINE(
ORDERNUMBER varchar(16) NOT NULL,
RMPHASE char(1) NOT NULL,
ORDERLINE char(2) NOT NULL,
ORDERID varchar(8) NOT NULL,
PRODUCT varchar(8) NOT NULL,
CONSTRAINT ORDERLINE_PK PRIMARY KEY CLUSTERED (ORDERNUMBER,ORDERLINE,RMPHASE)
)
CREATE TABLE dbo.PRODUCT(
PRODUCT varchar(8) NOT NULL,
FACTORY varchar(4) NULL,
CONSTRAINT PRODUCT_PK PRIMARY KEY CLUSTERED (PRODUCT)
)