তারিখের তুলনা সহ নিম্নতর পারফরম্যান্স সাবকোয়ারি


15

কোনও ম্যাচের ক্ষেত্রের সাথে সমস্ত পূর্ববর্তী রেকর্ডগুলির মোট গণনা সন্ধান করার জন্য যখন সাবকোয়ারি ব্যবহার করা হয়, তখন 50 কিলোমিটারেরও কম রেকর্ড সহ কোনও টেবিলে পারফরম্যান্স ভয়ানক। সাবকিউরিটি ব্যতীত ক্যোরিটি কয়েক মিলিসেকেন্ডে চালিত হয়। সাবকিউরির সাথে, কার্যকর করার সময়টি এক মিনিটের উপরে।

এই ক্যোয়ারির জন্য, ফলাফল অবশ্যই:

  • একটি নির্দিষ্ট তারিখের মধ্যে কেবল সেই রেকর্ডগুলি অন্তর্ভুক্ত করুন।
  • তারিখের সীমা নির্বিশেষে বর্তমান রেকর্ড সহ সমস্ত পূর্ববর্তী রেকর্ডগুলির একটি গণনা অন্তর্ভুক্ত করুন।

বেসিক টেবিল স্কিমা

Activity
======================
Id int Identifier
Address varchar(25)
ActionDate datetime2
Process varchar(50)
-- 7 other columns

উদাহরণ ডেটা

Id  Address     ActionDate (Time part excluded for simplicity)
===========================
99  000         2017-05-30
98  111         2017-05-30
97  000         2017-05-29
96  000         2017-05-28
95  111         2017-05-19
94  222         2017-05-30

প্রত্যাশিত ফলাফল

তারিখ সীমা 2017-05-29জন্য2017-05-30

Id  Address     ActionDate    PriorCount
=========================================
99  000         2017-05-30    2  (3 total, 2 prior to ActionDate)
98  111         2017-05-30    1  (2 total, 1 prior to ActionDate)
94  222         2017-05-30    0  (1 total, 0 prior to ActionDate)
97  000         2017-05-29    1  (3 total, 1 prior to ActionDate)

রেকর্ডস 96 এবং 95 ফলাফল থেকে বাদ দেওয়া হয়েছে, কিন্তু PriorCountsubquery অন্তর্ভুক্ত করা হয়

বর্তমান প্রশ্ন

select 
    *.a
    , ( select count(*) 
        from Activity
        where 
            Activity.Address = a.Address
            and Activity.ActionDate < a.ActionDate
    ) as PriorCount
from Activity a
where a.ActionDate between '2017-05-29' and '2017-05-30'
order by a.ActionDate desc

বর্তমান সূচি

CREATE NONCLUSTERED INDEX [IDX_my_nme] ON [dbo].[Activity]
(
    [ActionDate] ASC
)
INCLUDE ([Address]) WITH (
    PAD_INDEX = OFF, 
    STATISTICS_NORECOMPUTE = OFF, 
    SORT_IN_TEMPDB = OFF, 
    DROP_EXISTING = OFF, 
    ONLINE = OFF, 
    ALLOW_ROW_LOCKS = ON, 
    ALLOW_PAGE_LOCKS = ON
)

প্রশ্ন

  • এই কোয়েরির কার্যকারিতা উন্নত করতে কোন কৌশলগুলি ব্যবহার করা যেতে পারে?

1 সম্পাদনা করুন
আমি ডিবিতে কী পরিবর্তন করতে পারি এই প্রশ্নের জবাবে: আমি সূচিগুলি পরিবর্তন করতে পারি, কেবল সারণির কাঠামো নয় not

2 সম্পাদনা করুন
আমি এখন Addressকলামে একটি প্রাথমিক সূচক যুক্ত করেছি , তবে এটির খুব বেশি উন্নতি হবে বলে মনে হয় না। আমি বর্তমানে একটি টেম্প টেবিল তৈরি করে PriorCountএবং মানগুলি সন্নিবেশ করে এবং তারপরে প্রতিটি নির্দিষ্ট সীমাটি তাদের নির্দিষ্ট গণনা সহ আপডেট করার মাধ্যমে আরও ভাল পারফরম্যান্সটি খুঁজে পাচ্ছি ।

3 সম্পাদনা করুন
সূচক স্পুল জো ওবিশ (স্বীকৃত উত্তর) পাওয়া গেল বিষয়টি ছিল। একবার আমি একটি নতুন যুক্ত করার পরে nonclustered index [xyz] on [Activity] (Address) include (ActionDate), ক্যোরির সময়গুলি টেম্প টেবিলটি ব্যবহার না করে এক মিনিটের উপরে থেকে এক সেকেন্ডেরও কম চলে যায় (সম্পাদনা 2 দেখুন)।

উত্তর:


17

আপনার যে সূচী সংজ্ঞাটি রয়েছে তার সাথে IDX_my_nme, এসকিউএল সার্ভার ActionDateকলামটি ব্যবহার করতে সক্ষম হবে তবে কলামটি নয় Address। সূচকে সাবকোয়ারিটি আবরণ করার জন্য প্রয়োজনীয় সমস্ত কলাম রয়েছে তবে এটি সম্ভবত সাবকোয়ারির জন্য খুব বেশি নির্বাচনী নয়। ধরুন যে সারণীতে থাকা সমস্ত ডেটারই ActionDateআগের তুলনায় একটি মান রয়েছে '2017-05-30'। A -এর চাইতে ActionDate < '2017-05-30'প্রায় সব সূচক, যা আরও নিচে ফিল্টার করা হয় সারি পর থেকে সারির ফিরে আসবে সূচি থেকে পেয়েছে। যদি আপনার ক্যোয়ারী 200 টি সারি দেয় তবে আপনি সম্ভবত প্রায় 200 পূর্ণ সূচক স্ক্যান IDX_my_nmeকরতে পারবেন যার অর্থ আপনি সূচকটি থেকে 50000 * 200 = 10 মিলিয়ন সারি পড়বেন।

এটি সম্ভবত Addressআপনার উপবৃত্তির জন্য অনুসন্ধান করা আরও বেশি নির্বাচনী হতে পারে, যদিও আপনি আমাদের ক্যোয়ারী সম্পর্কে সম্পূর্ণ পরিসংখ্যানগত তথ্য দেননি যাতে এটি আমার পক্ষ থেকে অনুমান। তবে, ধরুন আপনি ন্যায়বিচারে একটি সূচক তৈরি করেন Addressএবং আপনার টেবিলের জন্য 10k স্বতন্ত্র মান রয়েছে Address। নতুন সূচকের সাথে, এসকিউএল সার্ভারের সাবকিউয়ের প্রতিটি সম্পাদনের জন্য সূচক থেকে কেবল 5 টি সারি প্রয়োজন হবে, সুতরাং আপনি সূচকটি থেকে 200 * 5 = 1000 সারি পড়তে পারবেন।

আমি এসকিউএল সার্ভার ২০১ against এর বিপরীতে পরীক্ষা করছি যাতে কিছুটা ছোট ছোট সিনট্যাক্স পার্থক্য থাকতে পারে। নীচে কিছু নমুনা তথ্য রয়েছে যাতে আমি ডেটা বিতরণের জন্য উপরের মতো অনুরূপ অনুমান করেছি:

CREATE TABLE #Activity (
    Id int NOT NULL,
    [Address] varchar(25) NULL,
    ActionDate datetime2 NULL,
    FILLER varchar(100),
    PRIMARY KEY (Id)
);

INSERT INTO #Activity WITH (TABLOCK)
SELECT TOP (50000) -- 50k total rows
x.RN
, x.RN % 10000 -- 10k unique addresses
, DATEADD(DAY, x.RN / 100, '20160201') -- 100 rows per day
, REPLICATE('Z', 100)
FROM
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
    FROM master..spt_values t1
    CROSS JOIN master..spt_values t2
) x;

CREATE NONCLUSTERED INDEX [IDX_my_nme] ON #Activity
([ActionDate] ASC) INCLUDE ([Address]);

প্রশ্নটিতে বর্ণিত হিসাবে আমি আপনার সূচক তৈরি করেছি। আমি এই ক্যোয়ারির বিপরীতে পরীক্ষা করছি যা প্রশ্নের মধ্যে থাকা একই ডেটা ফেরত দেয়:

select 
    a.*
    , ( select count(*) 
        from #Activity Activity
        where 
            Activity.[Address] = a.[Address]
            and Activity.ActionDate < a.ActionDate
    ) as PriorCount
from #Activity a
where a.ActionDate between '2017-05-29' and '2017-05-30'
order by a.ActionDate desc;

আমি একটি সূচক স্পুল পেতে। একটি বেসিক স্তরে এর অর্থ কী, ক্যোরি অপ্টিমাইজারটি অন-ফ্লাইয়ে একটি অস্থায়ী সূচক তৈরি করে কারণ সারণীর বিপরীতে বিদ্যমান সূচিগুলির কোনওটিই উপযুক্ত ছিল না।

সূচক স্পুল

কোয়েরিটি এখনও আমার জন্য দ্রুত শেষ হয়। সম্ভবত আপনি আপনার সিস্টেমে ইনডেক্স স্পুল অপ্টিমাইজেশন পাচ্ছেন না বা সারণির সংজ্ঞা বা ক্যোয়ারী সম্পর্কে আলাদা কিছু রয়েছে। শিক্ষামূলক উদ্দেশ্যে আমি OPTION (QUERYRULEOFF BuildSpool)সূচি স্পুলটি অক্ষম করতে একটি অননুমোদিত বৈশিষ্ট্যটি ব্যবহার করতে পারি । পরিকল্পনার মতো দেখতে এখানে দেখুন:

খারাপ সূচক সন্ধান করুন

সরল সূচীর সন্ধানের উপস্থিতিতে বোকা বোকা না। এসকিউএল সার্ভার সূচকটি থেকে প্রায় 10 মিলিয়ন সারি পড়ে:

সূচি থেকে 10 এম সারি

যদি আমি একাধিকবার কোয়েরিটি চালাচ্ছি তবে ক্যোরি অপটিমাইজারের প্রতিবার এটি সূচক তৈরি করা বোধগম্য নয়। আমি এই সূত্রের সামনে এমন একটি সূচক তৈরি করতে পারি যা এই প্রশ্নের জন্য আরও নির্বাচনী হবে:

CREATE NONCLUSTERED INDEX [IDX_my_nme_2] ON #Activity
([Address] ASC) INCLUDE (ActionDate);

পরিকল্পনাটি আগের মতো:

সূচী সন্ধান করুন

তবে নতুন সূচকের সাথে এসকিউএল সার্ভার সূচকটি থেকে কেবল 1000 টি সারি পড়ে। সারিগুলির 800 টি গণনা করতে ফিরে এসেছে। সূচকটি আরও নির্বাচনী হিসাবে সংজ্ঞায়িত করা যেতে পারে তবে এটি আপনার ডেটা বিতরণের উপর নির্ভর করে যথেষ্ট ভাল হতে পারে।

ভাল সন্ধান

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

SELECT t.*
FROM
(
    select 
        a.*
        , -1 + ROW_NUMBER() OVER (PARTITION BY [Address] ORDER BY ActionDate) PriorCount
    from #Activity a
) t
where t.ActionDate between '2017-05-29' and '2017-05-30'
order by t.ActionDate desc;

এই ক্যোয়ারী ডেটাগুলির একক স্ক্যান করে তবে একটি ব্যয়বহুল বাছাই ROW_NUMBER()করে এবং টেবিলের প্রতিটি সারিটির জন্য ফাংশন গণনা করে, তাই মনে হয় এখানে কিছু অতিরিক্ত কাজ হয়েছে:

খারাপ বাছাই

তবে, যদি আপনি সত্যিই সেই কোড প্যাটার্নটি পছন্দ করেন তবে আপনি আরও সূক্ষ্মতর করতে একটি সূচককে সংজ্ঞায়িত করতে পারেন:

CREATE NONCLUSTERED INDEX [IDX_my_nme] ON #Activity
([Address], [ActionDate]) INCLUDE (FILLER);

এটি বাছাইটি শেষের দিকে নিয়ে যায় যা অনেক কম ব্যয়বহুল হবে:

ভাল সাজান

যদি এর কোনওটিই সহায়তা না করে তবে আপনাকে যথাযথ বাস্তবায়ন পরিকল্পনা সহ আরও বেশি করে প্রশ্নে যুক্ত করতে হবে।


1
আপনি যে সূচক স্পুলটি পেয়েছেন সেটি ছিল সমস্যা। একবার আমি একটি নতুন যুক্ত করেছি nonclustered index [xyz] on [Activity] (Address) include (ActionDate), ক্যোয়ারির সময়গুলি এক মিনিটের উপর থেকে এক সেকেন্ডেরও কম চলে গেছে। +10 যদি আমি পারতাম। ধন্যবাদ!
মেট্রো স্মুরফ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.