দু'টি তারিখ কলামের জন্য সারেজযোগ্য যেখানে বিধি


24

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

USE [tempdb]
SET NOCOUNT ON  

IF OBJECT_ID('tempdb..#sargme') IS NOT NULL
BEGIN
DROP TABLE #sargme
END

SELECT TOP 1000
IDENTITY (BIGINT, 1,1) AS ID,
CAST(DATEADD(DAY, [m].[severity] * -1, GETDATE()) AS DATE) AS [DateCol1],
CAST(DATEADD(DAY, [m].[severity], GETDATE()) AS DATE) AS [DateCol2]
INTO #sargme
FROM sys.[messages] AS [m]

ALTER TABLE [#sargme] ADD CONSTRAINT [pk_whatever] PRIMARY KEY CLUSTERED ([ID])
CREATE NONCLUSTERED INDEX [ix_dates] ON [#sargme] ([DateCol1], [DateCol2])

আমি প্রায়শই যা দেখতে পাচ্ছি তা হ'ল এটির মতো:

/*definitely not sargable*/
SELECT
    * ,
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
    [#sargme] AS [s]
WHERE
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2]) >= 48;

... যা অবশ্যই SARGable নয় G এটি একটি সূচক স্ক্যানের ফলস্বরূপ, সমস্ত 1000 সারি পড়ে, কোনও ভাল নয়। আনুমানিক সারি দুর্গন্ধ। আপনি এটি কখনও উত্পাদন করতে চাই না in

না স্যার, আমার ভালো লাগেনি।

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

/*would be nice if it were sargable*/
WITH    [x] AS ( SELECT
                * ,
                DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2]) AS [ddif]
               FROM
                [#sargme] AS [s])
     SELECT
        *
     FROM
        [x]
     WHERE
        [x].[ddif] >= 48;

এবং অবশ্যই, যেহেতু আমরা ধ্রুবকগুলি ব্যবহার করছি না, এই কোডটি কিছুই পরিবর্তন করে না, এবং অর্ধেক SARGableও নয়। মজা নেই। একই বাস্তবায়ন পরিকল্পনা।

/*not even half sargable*/
SELECT
    * ,
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
    [#sargme] AS [s]
WHERE
    [s].[DateCol2] >= DATEADD(DAY, 48, [s].[DateCol1])

আপনি যদি ভাগ্যবান বোধ করছেন এবং আপনি যদি আপনার সংযোগের স্ট্রিংগুলিতে সমস্ত এএনএসআই সেট বিকল্পগুলি মানছেন, আপনি একটি গণিত কলাম যুক্ত করতে পারেন এবং এটি অনুসন্ধান করতে পারেন ...

ALTER TABLE [#sargme] ADD [ddiff] AS 
DATEDIFF(DAY, DateCol1, DateCol2) PERSISTED

CREATE NONCLUSTERED INDEX [ix_dates2] ON [#sargme] ([ddiff], [DateCol1], [DateCol2])

SELECT [s].[ID] ,
       [s].[DateCol1] ,
       [s].[DateCol2]
FROM [#sargme] AS [s]
WHERE [ddiff] >= 48

এটি আপনাকে তিনটি প্রশ্নের সাথে একটি সূচি সন্ধান করবে। বিজোড় মানুষটি হ'ল আমরা তারিখ 1 এ 48 দিন যুক্ত করি। সঙ্গে ক্যোয়ারী DATEDIFFমধ্যে WHEREদফা, CTEকম্পিউটেড কলাম একটি বিধেয় সঙ্গে, এবং চূড়ান্ত ক্যোয়ারী সব অনেক nicer অনুমান সঙ্গে একটি অনেক nicer পরিকল্পনা যে সব দিতে, এবং।

আমি এই সাথে থাকতে পারে।

যা আমাকে প্রশ্নে নিয়ে আসে: একটি একক ক্যোয়ারিতে, এই অনুসন্ধানটি করার কোনও SARGable উপায় আছে কি?

কোনও টেম্প টেবিল নেই, কোনও টেবিলের ভেরিয়েবল নেই, কোনও টেবিলের কাঠামোর পরিবর্তন হবে না এবং কোনও দর্শন নেই।

আমি স্ব-যোগদান করে, সিটিই, সাবকোয়ারি বা ডেটা একাধিক পাস দিয়ে ভাল fine এসকিউএল সার্ভারের যে কোনও সংস্করণ নিয়ে কাজ করতে পারে।

গণিত কলামটি এড়ানো একটি কৃত্রিম সীমাবদ্ধতা কারণ আমি অন্য কোনও কিছুর চেয়ে ক্যোয়ারী সমাধানে বেশি আগ্রহী।

উত্তর:


16

কেবল এটিকে দ্রুত যুক্ত করা যাতে এটি উত্তর হিসাবে উপস্থিত থাকে (যদিও আমি জানি এটি আপনি যে উত্তর চান তা নয়)।

একটি সূচকযুক্ত গণনা কলাম সাধারণত এই ধরণের সমস্যার সঠিক সমাধান।

এটা তোলে:

  • শিকারিকে একটি সূচিযোগ্য অভিব্যক্তি তৈরি করে
  • আরও ভাল কার্ডিনালিটি অনুমানের জন্য স্বয়ংক্রিয় পরিসংখ্যান তৈরি করার অনুমতি দেয়
  • বেস টেবিলের কোনও স্থান নেওয়ার দরকার নেই

এই শেষ পয়েন্টটি পরিষ্কার করার জন্য, গণনা করা কলামটি এই ক্ষেত্রে বজায় রাখতে হবে না :

-- Note: not PERSISTED, metadata change only
ALTER TABLE #sargme
ADD DayDiff AS DATEDIFF(DAY, DateCol1, DateCol2);

-- Index the expression
CREATE NONCLUSTERED INDEX index_name
ON #sargme (DayDiff)
INCLUDE (DateCol1, DateCol2);

এখন ক্যোয়ারী:

SELECT
    S.ID,
    S.DateCol1,
    S.DateCol2,
    DATEDIFF(DAY, S.DateCol1, S.DateCol2)
FROM
    #sargme AS S
WHERE
    DATEDIFF(DAY, S.DateCol1, S.DateCol2) >= 48;

... নিম্নলিখিত তুচ্ছ পরিকল্পনা দেয় :

হত্যা পরিকল্পনা

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

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

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


12

এসকিউএল সার্ভার সম্প্রদায়ের কয়েকটি বৃহত্তম নাম থেকে উপহাসের ঝুঁকি নিয়ে, আমি আমার ঘাড়ে আটকে রেখে বলছি, না।

আপনার কোয়েরিটি SARGable হওয়ার জন্য, আপনাকে মূলত এমন একটি ক্যোয়ারী তৈরি করতে হবে যা সূচকে ক্রমাগত সারিগুলির মধ্যে একটি প্রারম্ভিক সারি চিহ্নিত করতে পারে । সূচকের সাথে ix_dates, সারিগুলির মধ্যে DateCol1এবং তারিখের পার্থক্যের দ্বারা অর্ডার করা হয় না DateCol2, সুতরাং আপনার লক্ষ্য সারিগুলি সূচকের যে কোনও জায়গায় ছড়িয়ে যেতে পারে।

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

আরও সঠিক সারির প্রাক্কলন হিসাবে, তারিখের পার্থক্য সম্পর্কে কোনও পরিসংখ্যান নেই।

নিম্নলিখিত, মোটামুটি কুৎসিত recursive সিটিই নির্মাণ প্রযুক্তিগতভাবে পুরো টেবিলটি স্ক্যান করা বাদ দেয়, যদিও এটি একটি নেস্টেড লুপ যোগ এবং একটি (সম্ভাব্য খুব বড়) সংখ্যার সূচক সন্ধান করে introdu

DECLARE @from date, @count int;
SELECT TOP 1 @from=DateCol1 FROM #sargme ORDER BY DateCol1;
SELECT TOP 1 @count=DATEDIFF(day, @from, DateCol1) FROM #sargme WHERE DateCol1<=DATEADD(day, -48, {d '9999-12-31'}) ORDER BY DateCol1 DESC;

WITH cte AS (
    SELECT 0 AS i UNION ALL
    SELECT i+1 FROM cte WHERE i<@count)

SELECT b.*
FROM cte AS a
INNER JOIN #sargme AS b ON
    b.DateCol1=DATEADD(day, a.i, @from) AND
    b.DateCol2>=DATEADD(day, 48+a.i, @from)
OPTION (MAXRECURSION 0);

এটি DateCol1টেবিলের প্রত্যেকটি সমন্বিত একটি সূচক স্পুল তৈরি করে , তারপরে তাদের প্রত্যেকের জন্য একটি সূচক সিক (রেঞ্জ স্ক্যান) সম্পাদন করে DateCol1এবং DateCol2কমপক্ষে ৪৮ দিন এগিয়ে forward

আরও আইও, এক্সিকিউশন সময়টি সামান্য দীর্ঘ, সারি অনুমান এখনও বন্ধ রয়েছে এবং পুনরাবৃত্তির কারণে সমান্তরালনের শূন্য সম্ভাবনা: আমি অনুমান করছি যে এই প্রশ্নটি সম্ভবত কার্যকর হতে পারে যদি আপনার তুলনামূলকভাবে কয়েকটি স্বতন্ত্র, পরপর কিছুটা খুব বেশি সংখ্যক মান থাকে তবে DateCol1(সিক্সের সংখ্যা নীচে রেখে)।

ক্রেজি পুনরাবৃত্ত সিটিই কোয়েরি প্ল্যান


9

আমি একগুচ্ছ ঘাবড়ে যাওয়া বিভিন্ন প্রকারের চেষ্টা করেছি, তবে আপনার কোনওটির চেয়ে ভাল কোনও সংস্করণ পাইনি। মূল সমস্যাটি হ'ল তারিখ 1 এবং তারিখ 2 কীভাবে এক সাথে বাছাই করা হয় তার সূচীতে আপনার সূচিটি দেখতে এরকম দেখাচ্ছে। প্রথম কলামটি একটি দুর্দান্ত শেল্ভড লাইনে থাকবে যখন তাদের মধ্যকার ফাঁক খুব দুলতে থাকবে। আপনি এটি দেখতে চান যেভাবে এটি ফানেলের মতো দেখতে আরও চান:

Date1    Date2
-----    -------
*             *
*             *
*              *
 *       * 
 *        *
 *         *
  *      *
  *           *

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

আপনি বলেছিলেন যে এই ক্যোয়ারীটি কোনও মজাদার নয়, তবে আপনি যদি ঘনিষ্ঠভাবে দেখেন তবে এটি এখন পর্যন্ত সেরা (

SELECT
    * ,
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
    [#sargme] AS [s]
WHERE
    [s].[DateCol2] >= DATEADD(DAY, 48, [s].[DateCol1])

কারণ এড়ানো DATEDIFFসম্ভাব্য বিরুদ্ধে হিসাব তুলনায় কিছু সিপিইউ shaves শুধুমাত্র সূচক অ নেতৃস্থানীয় কী কলাম, এবং কিছু কদর্য অন্তর্নিহিত ধর্মান্তর এড়াতে datetimeoffset(7)(আমাকে জিজ্ঞাসা করবেন না কেন আছে, কিন্তু তারা আছে)। DATEDIFFসংস্করণটি এখানে :

<
প্রেডিকেট > <স্কেলার অপারেটর স্কেলারস্ট্রিং = "তারিখ (দিন, CONVERT_IMPLICIT (ডেটটাইমসেট (7), [স্প্লুঞ্জ]। [ডিবিও]। [সরগমে]। [ডেটকাল 1] [এস] হিসাবে। )), [বিভক্ত]। [ডিবিও] [[সরগমে] Col [তারিখ কল ২] হিসাবে [গুলি] [

এবং এটি ছাড়া এখানে একটি DATEDIFF:

<
প্রেডিকেট > <স্ক্যালার অপারেটার স্কেলারস্ট্রিং = "[স্প্লুঞ্জ]। [ডিবিও]। [সরগমে]। [ডেটকল 2] [এস] হিসাবে। [ডেটকল 2]> = ডেটড্ড (দিন, (48), [স্প্লুঞ্জ]। [ডিবিও]। [ডিবিও]। [ সরগমে]। [তারিখ কল 1] হিসাবে [গুলি] [

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

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

এবং এই সমস্ত বিষয় কত? আমি জানি না। আমি টেবিলটি 10 ​​মিলিয়ন সারি তৈরি করেছি এবং উপরের সমস্ত ক্যোয়ারী প্রকরণগুলি এখনও এক সেকেন্ডের মধ্যে সম্পূর্ণ completed এবং এটি ল্যাপটপের একটি ভিএম-তে রয়েছে (এসএসডি সহ অনুমোদিত)।


3

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

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

--Add this index to avoid the scan when determining the @MaxDate value
--CREATE NONCLUSTERED INDEX [ix_dates2] ON [#sargme] ([DateCol2]);
DECLARE @MinDate DATE, @MaxDate DATE;
SELECT @MinDate=DateCol1 FROM (SELECT TOP 1 DateCol1 FROM #sargme ORDER BY DateCol1 ASC) ss;
SELECT @MaxDate=DateCol2 FROM (SELECT TOP 1 DateCol2 FROM #sargme ORDER BY DateCol2 DESC) ss;

--Used 44 just to get a few more rows to test my logic
DECLARE @DateDiffSearchValue INT = 44, 
    @MinMaxDifference INT = DATEDIFF(DAY, @MinDate, @MaxDate);

--basic data profile in the table
SELECT [MinDate] = @MinDate, 
        [MaxDate] = @MaxDate, 
        [MinMaxDifference] = @MinMaxDifference, 
        [LastDate1SearchValue] = DATEADD(DAY, 0-@DateDiffSearchValue, @MaxDate);

;WITH rn_base AS (
SELECT [col1] = 0
        UNION ALL SELECT 0
        UNION ALL SELECT 0
        UNION ALL SELECT 0
),
rn_1 AS (
    SELECT t0.col1 FROM rn_base t0
        CROSS JOIN rn_base t1
        CROSS JOIN rn_base t2
        CROSS JOIN rn_base t3
),
rn_2 AS (
    SELECT rn = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
    FROM rn_1 t0
        CROSS JOIN rn_1 t1
),
candidate_searches AS (
    SELECT 
        [Date1_EqualitySearch] = DATEADD(DAY, t.rn-1, @MinDate),
        [Date2_RangeSearch] = DATEADD(DAY, t.rn-1+@DateDiffSearchValue, @MinDate)
    FROM rn_2 t
    WHERE DATEADD(DAY, t.rn-1, @MinDate) <= DATEADD(DAY, 0-@DateDiffSearchValue, @MaxDate)
    /* Of course, ignore row-number values that would result in a
       Date1_EqualitySearch value that is < @DateDiffSearchValue days before @MaxDate */
)
--select * from candidate_searches

SELECT c.*, xapp.*, dd_rows = DATEDIFF(DAY, xapp.DateCol1, xapp.DateCol2)
FROM candidate_searches c
    cross apply (
        SELECT t.*
        FROM #sargme t
        WHERE t.DateCol1 = c.date1_equalitysearch
        AND t.DateCol2 >= c.date2_rangesearch
    ) xapp
ORDER BY xapp.ID asc --xapp.DateCol1, xapp.DateCol2 

3

সম্প্রদায় উইকির উত্তরটি মূলত প্রশ্নটির সম্পাদনা হিসাবে প্রশ্ন লেখক যুক্ত করেছেন

কিছুটা বসে থাকার জন্য, এবং কিছু সত্যই স্মার্ট ব্যক্তিরা এটির জন্য চাপ দেওয়ার পরে, এই সম্পর্কে আমার প্রাথমিক চিন্তাটি সঠিক বলে মনে হচ্ছে: কোনও কলাম যুক্ত না করে এই কোয়েরিটি লেখার কোনও বুদ্ধিমান এবং SARGable উপায় নেই, হয় গণনা করা নয়, বা অন্য কোনও যন্ত্রে রক্ষণাবেক্ষণ করা হচ্ছে, যথা ট্রিগার।

আমি কয়েকটি অন্যান্য জিনিস চেষ্টা করে দেখেছি এবং আমার আরও কিছু পর্যবেক্ষণ রয়েছে যা পড়তে আগ্রহী বা নাও পারে।

প্রথমে কোনও টেম্প টেবিলের চেয়ে নিয়মিত টেবিল ব্যবহার করে সেটআপটি পুনরায় চালনা করুন

  • যদিও আমি তাদের খ্যাতি জানি, আমি বহু-কলামের পরিসংখ্যানগুলি চেষ্টা করে দেখতে চেয়েছিলাম। তারা অকেজো ছিল।
  • আমি দেখতে চেয়েছিলাম কোন পরিসংখ্যান ব্যবহৃত হয়েছিল

এখানে নতুন সেটআপ দেওয়া হল:

USE [tempdb]
SET NOCOUNT ON  

DBCC FREEPROCCACHE

IF OBJECT_ID('tempdb..sargme') IS NOT NULL
BEGIN
DROP TABLE sargme
END

SELECT TOP 1000
IDENTITY (BIGINT, 1,1) AS ID,
CAST(DATEADD(DAY, [m].[severity] * -1, GETDATE()) AS DATE) AS [DateCol1],
CAST(DATEADD(DAY, [m].[severity], GETDATE()) AS DATE) AS [DateCol2]
INTO sargme
FROM sys.[messages] AS [m]

ALTER TABLE [sargme] ADD CONSTRAINT [pk_whatever] PRIMARY KEY CLUSTERED ([ID])
CREATE NONCLUSTERED INDEX [ix_dates] ON [sargme] ([DateCol1], [DateCol2])

CREATE STATISTICS [s_sargme] ON [sargme] ([DateCol1], [DateCol2])

তারপরে, প্রথম ক্যোয়ারী চালিয়ে এটি ix_dates সূচক এবং স্ক্যানগুলি ব্যবহার করবে ঠিক আগের মতো। এখানে কোনও পরিবর্তন নেই। এটিকে অপ্রয়োজনীয় মনে হলেও আমার সাথে লেগে থাকুন।

SELECT
    * ,
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
    [sargme] AS [s]
WHERE
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2]) >= 48

আবার সিটিই ক্যোয়ারি চালান, এখনও একই ...

WITH    [x] AS ( SELECT
                * ,
                DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2]) AS [ddif]
               FROM
                [sargme] AS [s])
     SELECT
        *
     FROM
        [x]
     WHERE
        [x].[ddif] >= 48;

ঠিক আছে! না-এমনকি-অর্ধ-সরজযোগ্য ক্যোয়ারী আবার চালান:

SELECT
    * ,
    DATEDIFF(DAY, [s].[DateCol1], [s].[DateCol2])
FROM
    [sargme] AS [s]
WHERE
    [s].[DateCol2] >= DATEADD(DAY, 48, [s].[DateCol1])

এখন গণিত কলাম যুক্ত করুন এবং গণিত কলামটিতে আঘাতের ক্যোয়ারী সহ তিনটিই আবার চালিত করুন:

ALTER TABLE [sargme] ADD [ddiff] AS 
DATEDIFF(DAY, DateCol1, DateCol2) PERSISTED

CREATE NONCLUSTERED INDEX [ix_dates2] ON [sargme] ([ddiff], [DateCol1], [DateCol2])

SELECT [s].[ID] ,
       [s].[DateCol1] ,
       [s].[DateCol2]
FROM [sargme] AS [s]
WHERE [ddiff] >= 48

আপনি যদি এখানে আমার সাথে আটকে থাকেন, ধন্যবাদ এটি পোস্টের আকর্ষণীয় পর্যবেক্ষণ অংশ।

দ্বারা একটি অনথিভুক্ত ট্রেস পতাকা দিয়ে একটি ক্যোয়ারী চালনা Fabiano মধ্যে Amorim যা দেখতে পরিসংখ্যান ব্যবহৃত প্রতিটি প্রশ্নের সাথে বেশ কুল। দেখতে দেখতে যে কোন পরিকল্পনা স্পর্শ একটি পরিসংখ্যান আপত্তি পর্যন্ত কম্পিউটেড কলাম তৈরি করা হয়েছে এবং বিজোড় করলো ইন্ডেক্স।

ব্লাডক্লট কি

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

অন্য একটি বিষয় যা এখানে ভ্রু উত্থাপন করেছে তা হ'ল আমি যখন কেবল নন-ক্ল্লাস্টার্ড সূচক যুক্ত করেছি, কোয়েরিটি উভয় তারিখের কলামগুলিতে নন-ক্ল্লাস্টার্ড সূচক ব্যবহার না করে সমস্ত এইচএপি স্ক্যান করার পরিকল্পনা করে।

প্রতিক্রিয়া ধন্যবাদ সবাই কে. আপনি সব দুর্দান্ত।

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