বহিরাগত গণিত কলামে সূচককে গণিত অভিব্যক্তিতে কলাম পেতে চাবি দরকার


24

আমার একটি টেবিলের উপর অবিরাম গণিত কলাম রয়েছে যা খালি খাঁটি কলামগুলি তৈরি করা হয়, যেমন

CREATE TABLE dbo.T 
(   
    ID INT IDENTITY(1, 1) NOT NULL CONSTRAINT PK_T_ID PRIMARY KEY,
    A VARCHAR(20) NOT NULL,
    B VARCHAR(20) NOT NULL,
    C VARCHAR(20) NOT NULL,
    D DATE NULL,
    E VARCHAR(20) NULL,
    Comp AS A + '-' + B + '-' + C PERSISTED NOT NULL 
);

এটিতে Compঅনন্য নয়, এবং ডি এর প্রতিটি সংমিশ্রণের তারিখ থেকে বৈধ A, B, C, সুতরাং আমি প্রত্যেকের শেষের তারিখ পেতে নিম্নলিখিত কোয়েরিটি ব্যবহার করি A, B, C(মূলত কমপের একই মানের জন্য পরবর্তী সূচনা তারিখ):

SELECT  t1.ID,
        t1.Comp,
        t1.D,
        D2 = (  SELECT  TOP 1 t2.D
                FROM    dbo.T t2
                WHERE   t2.Comp = t1.Comp
                AND     t2.D > t1.D
                ORDER BY t2.D
            )
FROM    dbo.T t1
WHERE   t1.D IS NOT NULL -- DON'T CARE ABOUT INACTIVE RECORDS
ORDER BY t1.Comp;

আমি তখন এই ক্যোয়ারীতে সহায়তা করার জন্য গণিত কলামে একটি সূচক যুক্ত করেছি (এবং অন্যরাও):

CREATE NONCLUSTERED INDEX IX_T_Comp_D ON dbo.T (Comp, D) WHERE D IS NOT NULL;

ক্যোয়ারী প্ল্যানটি তবে আমাকে অবাক করেছে। আমি ভেবেছি যেহেতু আমার কাছে এমন একটি ধারা রয়েছে যা উল্লেখ করে D IS NOT NULLআমি বাছাই করছি Comp, এবং সূচকের বাইরে কোনও কলামকে উল্লেখ করছি না যে গণনা করা কলামের সূচকটি টি 1 এবং টি 2 স্ক্যান করতে ব্যবহার করা যেতে পারে তবে আমি একটি ক্লাস্টার্ড সূচক দেখেছি স্ক্যান.

এখানে চিত্র বর্ণনা লিখুন

সুতরাং আমি এই সূচকটি ব্যবহার করতে আরও বাধ্য করলাম এটি আরও ভাল পরিকল্পনা এনেছে কিনা:

SELECT  t1.ID,
        t1.Comp,
        t1.D,
        D2 = (  SELECT  TOP 1 t2.D
                FROM    dbo.T t2
                WHERE   t2.Comp = t1.Comp
                AND     t2.D > t1.D
                ORDER BY t2.D
            )
FROM    dbo.T t1 WITH (INDEX (IX_T_Comp_D))
WHERE   t1.D IS NOT NULL
ORDER BY t1.Comp;

যা এই পরিকল্পনা দিয়েছে

এখানে চিত্র বর্ণনা লিখুন

এটি দেখায় যে একটি কী লুকআপ ব্যবহৃত হচ্ছে, তার বিবরণগুলি:

এখানে চিত্র বর্ণনা লিখুন

এখন, এসকিউএল-সার্ভার ডকুমেন্টেশন অনুসারে:

আপনি একটি গণনাকারী কলামে একটি সূচক তৈরি করতে পারেন যা নির্ধারিত সংজ্ঞাযুক্ত, তবে অসম্পূর্ণ, অভিব্যক্তিটি তৈরি করা হয়েছে যদি কলামটি সারণী তৈরি বা টেবিল স্টেটমেন্ট বিবৃতিতে পার্স্টিস্ট চিহ্নিত করা থাকে। এর অর্থ হ'ল ডাটাবেস ইঞ্জিনটি সারণীতে গণিত মানগুলি সংরক্ষণ করে এবং যখন কোনও অন্যান্য কলাম যার উপর নির্ভর করে গণনা করা কলামটি আপডেট করা থাকে সেগুলি আপডেট করে। ডেটাবেস ইঞ্জিন কলামে একটি সূচক তৈরি করার সময়, এবং যখন সূচীটি কোনও প্রশ্নে রেফারেন্স করা হয় তখন এই স্থায়ী মানগুলি ব্যবহার করে। এই বিকল্পটি আপনাকে একটি গণিত কলামে একটি সূচক তৈরি করতে সক্ষম করে যখন ডাটাবেস ইঞ্জিন নির্ভুলতার সাথে প্রমাণ করতে পারে না যে কোনও ফাংশন যা গণিত কলামের এক্সপ্রেশনগুলি ফিরিয়ে দেয়, বিশেষত একটি সিএলআর ফাংশন যা .NET ফ্রেমওয়ার্কে তৈরি হয়, উভয়ই নির্বিচারক এবং নির্ভুল।

সুতরাং, যদি ডক্স হিসাবে "ডাটাবেস ইঞ্জিনটি সারণীতে গণিত মানগুলি সংরক্ষণ করে " বলে , এবং মানটি আমার সূচকগুলিতেও সঞ্চয় করা হয়, তখন কেন, এ, বি এবং সি প্রাপ্ত করার জন্য কী লুপআপের প্রয়োজন হয়? প্রশ্নটি আদৌ? আমি ধরে নিলাম সেগুলি কমপ গণনা করতে ব্যবহৃত হচ্ছে, তবে কেন? এছাড়াও, কেন কোয়েরি সূচকটি চালু রাখতে পারে t2, তবে চালু হয় না t1?

এসকিউএল ফিডেলে প্রশ্ন এবং ডিডিএল

এনবি আমি এসকিউএল সার্ভার ২০০৮-এ ট্যাগ করেছি কারণ এটিই হ'ল সংস্করণ যে আমার মূল সমস্যাটি রয়েছে তবে আমি ২০১২ সালেও একই আচরণ পেয়েছি।

উত্তর:


20

এ, বি এবং সি যখন কোয়েরিতে একেবারেই রেফারেন্স করা হয়নি তখন কী কী লুপআপের প্রয়োজন? আমি ধরে নিলাম সেগুলি কমপ গণনা করতে ব্যবহৃত হচ্ছে, তবে কেন?

কলাম A, B, and C হয় ক্যোয়ারী পরিকল্পনা উল্লেখ - তারা দ্বারা ব্যবহৃত হয় উপর চাইতে T2

এছাড়াও, কেন কোয়েরি টি 2 তে সূচকটি ব্যবহার করতে পারে, তবে টি 1 তে নয়?

অপ্টিমাইজার সিদ্ধান্ত নিয়েছে যে ক্লাস্টারড ইনডেক্স স্ক্যান করা ফিল্টারযুক্ত ননক্র্লাস্টারড ইনডেক্স স্ক্যান করার চেয়ে সস্তা এবং তারপরে এ, বি এবং সি কলামগুলির মানগুলি পুনরুদ্ধার করার জন্য একটি অনুসন্ধান সম্পাদন করে che

ব্যাখ্যা

আসল প্রশ্ন হ'ল অপ্টিমাইজার কেন সূচকটি সন্ধান করার জন্য এ, বি এবং সি পুনরুদ্ধার করার প্রয়োজনীয়তা অনুভব করেছিল। আমরা আশা করব এটি Compএকটি ননক্র্লাস্টারড ইনডেক্স স্ক্যান ব্যবহার করে কলামটি পড়বে এবং তারপরে শীর্ষ 1 রেকর্ডটি সনাক্ত করতে একই সূচীতে (ওরফে টি 2) সন্ধান করবে।

কোয়েরি অপ্টিমাইজারটি বিভিন্ন ক্যোয়ারী পরিকল্পনার ব্যয় নির্ধারণের সুযোগ দেওয়ার জন্য, অপ্টিমাইজেশন শুরুর আগে গণিত কলামের রেফারেন্সগুলি প্রসারিত করে। কিছু প্রশ্নের জন্য, একটি গণিত কলামের সংজ্ঞাটি প্রসারিত করা অপ্টিমাইজারকে আরও দক্ষ পরিকল্পনাগুলি সন্ধান করার অনুমতি দেয়।

অপ্টিমাইজারটি যখন কোনও সম্পর্কযুক্ত সাব-কোয়ের মুখোমুখি হয়, তখন এটি এমন ফর্মটিতে 'এটি তালিকাভুক্তকরণ' করার চেষ্টা করে যার পক্ষে যুক্তি করা সহজ হয়। যদি এটি আরও কার্যকর সরলীকরণের সন্ধান করতে না পারে, তবে এটি প্রয়োগ (একটি সম্পর্কযুক্ত যোগ) হিসাবে সম্পর্কযুক্ত সাব-কোয়েরিকে পুনরায় লেখার জন্য রিসর্ট করে:

পুনর্লিখন প্রয়োগ করুন

এটি ঠিক তাই ঘটে যে এটি অনিয়ন্ত্রিত প্রয়োগটি যৌক্তিক ক্যোয়ারী ট্রিটিকে এমন একটি ফর্মের মধ্যে রাখে যা প্রকল্পের সাধারণীকরণের সাথে ভাল কাজ করে না (পরবর্তী পর্যায়ে যা অন্যান্য বিষয়গুলির মধ্যে গণিত কলামগুলির সাথে সাধারণ প্রকাশের সাথে মেলে বলে মনে হয়)।

আপনার ক্ষেত্রে, ক্যোয়ারীটি যেভাবে রচিত হয়েছে তা অপ্টিমাইজারের অভ্যন্তরীণ বিশদগুলির সাথে মিথস্ক্রিয়া করে যে প্রসারিত অভিব্যক্তি সংজ্ঞাটি সংযুক্ত কলামের সাথে আর মিলছে না এবং আপনি শেষের A, B, and Cদিকে এই গণনা কলামের পরিবর্তে কলামগুলি উল্লেখ করে সন্ধান করতে পারেন Comp। এটিই মূল কারণ।

কার্যসংক্রান্ত

এই পার্শ্ব-প্রতিক্রিয়াটিকে একত্রিত করার একটি ধারণা হ'ল ম্যানুয়ালি প্রয়োগ হিসাবে ক্যোয়ারীটি লেখা:

SELECT
    T1.ID,
    T1.Comp,
    T1.D,
    CA.D2
FROM dbo.T AS T1
CROSS APPLY
(  
    SELECT TOP (1)
        D2 = T2.D
    FROM dbo.T AS T2
    WHERE
        T2.Comp = T1.Comp
        AND T2.D > T1.D
    ORDER BY
        T2.D ASC
) AS CA
WHERE
    T1.D IS NOT NULL -- DON'T CARE ABOUT INACTIVE RECORDS
ORDER BY
    T1.Comp;

দুর্ভাগ্যক্রমে, এই ক্যোয়ারী ফিল্টারড সূচকটি ব্যবহার করবে না কারণ আমরা আশা করি। Dপ্রয়োগের অভ্যন্তরে কলামে বৈষম্য পরীক্ষা প্রত্যাখ্যান করে NULLs, তাই আপাতদৃষ্টিতে অপ্রয়োজনীয় ভবিষ্যদ্বাণীটি WHERE T1.D IS NOT NULLঅপ্টিমাইজ করা হয়েছে।

সুস্পষ্ট ভবিষ্যদ্বাণী ছাড়াই, ফিল্টারড সূচকগুলির সাথে মিলে যুক্তি সিদ্ধান্ত নেয় যে এটি ফিল্টার সূচকটি ব্যবহার করতে পারে না। এই দ্বিতীয় পার্শ্ব-প্রতিক্রিয়াটির চারপাশে কাজ করার বেশ কয়েকটি উপায় রয়েছে তবে সম্ভবত সবচেয়ে সহজেই হ'ল ক্রস প্রয়োগ করা বাহ্যিক প্রয়োগের ক্ষেত্রে প্রয়োগ করা (সংযুক্ত সাবকোয়রিতে পূর্বে সম্পাদিত পুনর্লিখনের অপ্রয়োজনীয়টির যুক্তির প্রতিচ্ছবি):

SELECT
    T1.ID,
    T1.Comp,
    T1.D,
    CA.D2
FROM dbo.T AS T1
OUTER APPLY
(  
    SELECT TOP (1)
        D2 = T2.D
    FROM dbo.T AS T2
    WHERE
        T2.Comp = T1.Comp
        AND T2.D > T1.D
    ORDER BY
        T2.D ASC
) AS CA
WHERE
    T1.D IS NOT NULL -- DON'T CARE ABOUT INACTIVE RECORDS
ORDER BY
    T1.Comp;

এখন অপ্টিমাইজারটি প্রয়োগ পুনরায় রাইটিং নিজেই ব্যবহার করার প্রয়োজন নেই (সুতরাং গণিত কলামের মিলটি প্রত্যাশার মতো কাজ করে) এবং প্রিডিকেটটি অপ্টিমাইজ করা হয় না, তাই ফিল্টারড সূচক উভয় ডেটা অ্যাক্সেস অপারেশনের জন্য ব্যবহার করা যেতে পারে, এবং Compসন্ধানটি কলামটি ব্যবহার করে দুপাশে:

আউটার প্রয়োগ পরিকল্পনা

INCLUDEdফিল্টারড সূচকে কলাম হিসাবে এ, বি, এবং সি যুক্ত করার চেয়ে সাধারণত এটি পছন্দ করা হবে , কারণ এটি সমস্যার মূল কারণ হিসাবে সম্বোধন করে এবং অযথা সূচককে প্রশস্ত করার প্রয়োজন হয় না।

গণিত কলামগুলি তৈরি করেছে

পার্শ্ব নোট হিসাবে PERSISTED, গণিত কলামটি চিহ্নিত করার দরকার নেই, যদি আপনি তার CHECKসীমাবদ্ধতার মধ্যে এর সংজ্ঞাটি পুনরাবৃত্তি করতে আপত্তি করেন না :

CREATE TABLE dbo.T 
(   
    ID integer IDENTITY(1, 1) NOT NULL,
    A varchar(20) NOT NULL,
    B varchar(20) NOT NULL,
    C varchar(20) NOT NULL,
    D date NULL,
    E varchar(20) NULL,
    Comp AS A + '-' + B + '-' + C,

    CONSTRAINT CK_T_Comp_NotNull
        CHECK (A + '-' + B + '-' + C IS NOT NULL),

    CONSTRAINT PK_T_ID 
        PRIMARY KEY (ID)
);

CREATE NONCLUSTERED INDEX IX_T_Comp_D
ON dbo.T (Comp, D) 
WHERE D IS NOT NULL;

PERSISTEDযদি আপনি কোনও NOT NULLসীমাবদ্ধতা ব্যবহার করতে চান বা Compকলামটি সরাসরি (তার সংজ্ঞাটি পুনরাবৃত্ত করার পরিবর্তে) কোনও CHECKসীমাবদ্ধতার মধ্যে উল্লেখ করতে চান তবে এই ক্ষেত্রে গণিত কলামটি হওয়া দরকার ।


2
+1 বিটিডাব্লু আমি অনাবশ্যকভাবে দেখার জন্য অন্য একটি ঘটনা পেয়েছিলাম যখন আপনি এটি দেখতে আগ্রহী (বা নাও) পেতে পারেন। এসকিউএল ফিডল
মার্টিন স্মিথ

@ মার্টিনস্মিথ হ্যাঁ এটি আকর্ষণীয়। আর একটি জেনেরিক নিয়ম পুনর্লিখন ( FOJNtoLSJNandLASJN) এর ফলাফল যা আমরা প্রত্যাশা মতো কাজ না করে এবং জাঙ্ক (বেসরউ / চেকসামস) ছেড়ে যায় যা কিছু ধরণের পরিকল্পনায় কার্যকর (যেমন কার্সার) তবে এখানে প্রয়োজন হয় না।
পল হোয়াইট GoFundMonica বলেছেন

আহ Chkচেকসাম! ধন্যবাদ আমি সে সম্পর্কে নিশ্চিত ছিলাম না। মূলত আমি ভাবছিলাম এটি চেক সীমাবদ্ধতার সাথে করার মতো কিছু হতে পারে।
মার্টিন স্মিথ

6

যদিও আপনার পরীক্ষার ডেটার কৃত্রিম প্রকৃতির কারণে এটি কিছুটা সহ-ঘটনা হতে পারে, আপনি এসকিউএল 2012 উল্লেখ করেছেন বলে আমি পুনরায় লেখার চেষ্টা করেছি:

SELECT  ID,
        Comp,
        D,
        D2 = LEAD(D) OVER(PARTITION BY COMP ORDER BY D)
FROM    dbo.T 
WHERE   D IS NOT NULL
ORDER BY Comp;

এটি আপনার সূচকটি ব্যবহার করে এবং অন্যান্য বিকল্পগুলির তুলনায় (এবং আপনার পরীক্ষার ডেটার জন্য একই ফলাফল) তুলনায় উল্লেখযোগ্যভাবে কম পড়ার সাথে একটি দুর্দান্ত স্বল্প ব্যয়ের পরিকল্পনা পেয়েছে।

প্ল্যান এক্সপ্লোরারের চারটি বিকল্পের জন্য ব্যয়: মূল;  ইঙ্গিত সহ আসল;  বাইরের প্রয়োগ এবং সীসা

আমি সন্দেহ করি যে আপনার আসল ডেটা আরও জটিল তাই এমন কিছু পরিস্থিতি থাকতে পারে যেখানে এই ক্যোয়ারীটি আপনার কাছে শব্দার্থগতভাবে আলাদা আচরণ করে, তবে এটি কখনও কখনও নতুন বৈশিষ্ট্যগুলিতে বাস্তব পার্থক্য করতে পারে তা দেখায়।

আমি আরও কিছু বিচিত্র ডেটা নিয়ে পরীক্ষা-নিরীক্ষা করেছি এবং কিছু দৃশ্য মেলে এবং কিছুটি খুঁজে পেয়েছি:

--Example 1: results matched
TRUNCATE TABLE dbo.t

-- Generate some more interesting test data
;WITH cte AS
(
SELECT TOP 1000 ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 ) ) rn
FROM master.sys.columns c1
    CROSS JOIN master.sys.columns c2
    CROSS JOIN master.sys.columns c3
)
INSERT T (A, B, C, D)
SELECT  'A' + CAST( a.rn AS VARCHAR(5) ),
        'B' + CAST( a.rn AS VARCHAR(5) ),
        'C' + CAST( a.rn AS VARCHAR(5) ),
        DATEADD(DAY, a.rn + b.rn, '1 Jan 2013')
FROM cte a
    CROSS JOIN cte b
WHERE a.rn % 3 = 0
 AND b.rn % 5 = 0
ORDER BY 1, 2, 3
GO


-- Original query
SELECT  t1.ID,
        t1.Comp,
        t1.D,
        D2 = (  SELECT  TOP 1 D
                FROM    dbo.T t2
                WHERE   t2.Comp = t1.Comp
                AND     t2.D > t1.D
                ORDER BY D
            )
INTO #tmp1
FROM    dbo.T t1 
WHERE   t1.D IS NOT NULL
ORDER BY t1.Comp;
GO

SELECT  ID,
        Comp,
        D,
        D2 = LEAD(D) OVER(PARTITION BY COMP ORDER BY D)
INTO #tmp2
FROM    dbo.T 
WHERE   D IS NOT NULL
ORDER BY Comp;
GO


-- Checks ...
SELECT * FROM #tmp1
EXCEPT
SELECT * FROM #tmp2

SELECT * FROM #tmp2
EXCEPT
SELECT * FROM #tmp1


Example 2: results did not match
TRUNCATE TABLE dbo.t

-- Generate some more interesting test data
;WITH cte AS
(
SELECT TOP 1000 ROW_NUMBER() OVER ( ORDER BY ( SELECT 1 ) ) rn
FROM master.sys.columns c1
    CROSS JOIN master.sys.columns c2
    CROSS JOIN master.sys.columns c3
)
INSERT T (A, B, C, D)
SELECT  'A' + CAST( a.rn AS VARCHAR(5) ),
        'B' + CAST( a.rn AS VARCHAR(5) ),
        'C' + CAST( a.rn AS VARCHAR(5) ),
        DATEADD(DAY, a.rn, '1 Jan 2013')
FROM cte a

-- Add some more data
INSERT dbo.T (A, B, C, D)
SELECT A, B, C, D 
FROM dbo.T
WHERE DAY(D) In ( 3, 7, 9 )


INSERT dbo.T (A, B, C, D)
SELECT A, B, C, DATEADD( day, 1, D )
FROM dbo.T
WHERE DAY(D) In ( 12, 13, 17 )


SELECT * FROM #tmp1
EXCEPT
SELECT * FROM #tmp2

SELECT * FROM #tmp2
EXCEPT
SELECT * FROM #tmp1

SELECT * FROM #tmp2
INTERSECT
SELECT * FROM #tmp1


select * from #tmp1
where comp = 'A2-B2-C2'

select * from #tmp2
where comp = 'A2-B2-C2'

1
ওয়েল এটি সূচকটি ব্যবহার করে তবে কেবল একটি পয়েন্ট পর্যন্ত। যদি compকোনও গণিত কলাম না হয় তবে আপনি বাছাই করতে পারবেন না।
মার্টিন স্মিথ

ধন্যবাদ। আমার আসল পরিস্থিতি খুব জটিল নয় এবং LEADফাংশনটি ঠিক আমার স্থানীয় ২০১২ সালের মতামতের মতো প্রকাশিত হয়েছে। দুর্ভাগ্যক্রমে, আমার কাছে এই সামান্য অসুবিধাকে এখনও প্রোডাকশন সার্ভারগুলিকে আপগ্রেড করার পক্ষে যথেষ্ট উপযুক্ত কারণ বলে মনে করা হয়নি ...
গ্যারেথডি

-1

যখন আমি একই ক্রিয়াগুলি সম্পাদন করার চেষ্টা করেছি তখন একটির অন্য ফলাফল পেয়েছে। প্রথমত, সূচি ছাড়াই সারণির জন্য আমার সম্পাদনের পরিকল্পনাটি নীচের মত দেখাচ্ছে:এখানে চিত্র বর্ণনা লিখুন

যেমনটি আমরা ক্লাস্টারড ইনডেক্স স্ক্যান (টি 2) থেকে দেখতে পাচ্ছি, প্রিনিকেটটি প্রয়োজনীয় সারিগুলি (শর্তের কারণে) ফেরত দেওয়ার জন্য নির্ধারণ করতে ব্যবহৃত হয়:

এখানে চিত্র বর্ণনা লিখুন

যখন সূচকটি যুক্ত করা হয়েছিল, এটি WITH অপারেটর বা না দ্বারা সংজ্ঞায়িত করা বিষয় নয়, কার্যকর করার পরিকল্পনাটি নিম্নলিখিত হিসাবে পরিণত হয়েছিল:

এখানে চিত্র বর্ণনা লিখুন

যেমন আমরা দেখতে পাচ্ছি, ক্লাস্টারড ইনডেক্স স্ক্যান সূচি স্ক্যান দ্বারা প্রতিস্থাপিত হয়। যেমন আমরা উপরে দেখেছি, এসকিউএল সার্ভার নেস্টেড ক্যোয়ারির মিলটি সম্পাদনের জন্য গণিত কলামের উত্স কলামগুলি ব্যবহার করে। ক্লাস্টারড ইনডেক্স স্ক্যান চলাকালীন একই সময়ে এই সমস্ত মানগুলি অর্জন করা যেতে পারে (অতিরিক্ত ক্রিয়াকলাপের প্রয়োজন নেই)। যখন সূচকটি যুক্ত করা হয়েছিল, সারণী থেকে প্রয়োজনীয় মূল সারিগুলির ফিল্টারিং (প্রধান নির্বাচনের ক্ষেত্রে) সূচী অনুসারে কাজ করছে, তবে গণিত কলামের উত্স কলামগুলির মানগুলি compএখনও অর্জন করতে হবে (শেষ অপারেশন নেস্টেড লুপ) ।

এখানে চিত্র বর্ণনা লিখুন

এই কারণে কী লুকআপ অপারেশন ব্যবহৃত হয় - গণিতটির উত্স কলামগুলির ডেটা পেতে।

পিএস দেখতে এসকিউএল সার্ভারে বাগের মতো দেখাচ্ছে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.