কেন এটি দ্রুত এবং এটি ব্যবহার করা নিরাপদ? (যেখানে প্রথম অক্ষর বর্ণমালায় রয়েছে)


10

দীর্ঘ গল্প সংক্ষিপ্ত, আমরা একটি খুব বড় লোকের মানগুলির সাথে ছোট ছোট টেবিলগুলি আপডেট করছি। সাম্প্রতিক পরীক্ষায়, এই আপডেটটি চালাতে সিএ 5 মিনিট সময় নেয়।

সম্ভাব্যতম সর্বাধিক অপ্টিমাইজেশনের মতো যা বলে মনে হচ্ছে আমরা তাতে হোঁচট খেয়েছি, যা আপাতদৃষ্টিতে পুরোপুরি কার্যকর হয়! একই ক্যোয়ারী এখন 2 মিনিটেরও কম সময়ে চলে এবং পুরো ফলাফলটি পুরোপুরি উত্পন্ন করে।

কোয়েরি এখানে। শেষ লাইনটি "অনুকূলিতকরণ" হিসাবে যুক্ত করা হয়েছে। কেন কোয়েরি সময়ের তীব্র হ্রাস? আমরা কি কিছু মিস করছি? এটি কি ভবিষ্যতে সমস্যার সৃষ্টি করতে পারে?

UPDATE smallTbl
SET smallTbl.importantValue = largeTbl.importantValue
FROM smallTableOfPeople smallTbl
JOIN largeTableOfPeople largeTbl
    ON largeTbl.birth_date = smallTbl.birthDate
    AND DIFFERENCE(TRIM(smallTbl.last_name),TRIM(largeTbl.last_name)) = 4
    AND DIFFERENCE(TRIM(smallTbl.first_name),TRIM(largeTbl.first_name)) = 4
WHERE smallTbl.importantValue IS NULL
-- The following line is "the optimization"
AND LEFT(TRIM(largeTbl.last_name), 1) IN ('a','à','á','b','c','d','e','è','é','f','g','h','i','j','k','l','m','n','o','ô','ö','p','q','r','s','t','u','ü','v','w','x','y','z','æ','ä','ø','å')

প্রযুক্তিগত নোট: আমরা সচেতন যে পরীক্ষার জন্য বর্ণগুলির তালিকার জন্য আরও কয়েকটি অক্ষরের প্রয়োজন হতে পারে। "DIFFERENCE" ব্যবহার করার সময় আমরা ত্রুটির জন্য সুস্পষ্ট মার্জিন সম্পর্কেও অবগত।

ক্যোয়ারী প্ল্যান (নিয়মিত): https://www.brentozar.com/pastetheplan/?id=rypV84y7V
ক্যোয়ারী প্ল্যান ("অপ্টিমাইজেশন" সহ): https://www.brentozar.com/pastetheplan/?id=r1aC2my7E


4
আপনার প্রযুক্তিগত নোটটির ছোট্ট জবাব: আপনার AND LEFT(TRIM(largeTbl.last_name), 1) BETWEEN 'a' AND 'z' COLLATE LATIN1_GENERAL_CI_AIসমস্ত অক্ষর তালিকাভুক্ত করার প্রয়োজন নেই এবং পড়তে
এরিক এ

আপনার কি এমন সারি রয়েছে যেখানে চূড়ান্ত শর্তটি WHEREমিথ্যা? বিশেষ দ্রষ্টব্য যে তুলনাটি কেস সংবেদনশীল হতে পারে।
jpmc26

@ এরিকভন অ্যাসমূথ একটি দুর্দান্ত পয়েন্ট করেছেন। তবে, কেবল একটি ছোট প্রযুক্তিগত নোট: এসকিউএল সার্ভার ২০০৮ এবং ২০০৮ আর 2 এর জন্য, "100" সংস্করণ (সংস্কৃতি / স্থানীয় ব্যবহারের জন্য উপলব্ধ থাকলে) সংস্করণটি ব্যবহার করা ভাল। সুতরাং যে হবে Latin1_General_100_CI_AI। এবং এসকিউএল সার্ভার ২০১২ এবং আরও নতুনর জন্য (কমপক্ষে এসকিউএল সার্ভার 2019 এর মাধ্যমে), লোকেল ব্যবহারের জন্য সর্বাধিক সংস্করণে পরিপূরক চরিত্র-সক্ষম কলোশনগুলি ব্যবহার করা ভাল। সুতরাং যে Latin1_General_100_CI_AI_SCএই ক্ষেত্রে হবে। সংস্করণ> 100 (কেবলমাত্র জাপানি) এর (বা প্রয়োজন) নেই _SC(যেমন Japanese_XJIS_140_CI_AI)।
সলোমন রুটজকি

উত্তর:


9

এটি আপনার টেবিলগুলির তথ্যগুলি, আপনার সূচীগুলিতে, উপর নির্ভর করে .... কার্যকর করার পরিকল্পনাগুলি / আইও + সময়ের পরিসংখ্যানগুলির তুলনা করতে সক্ষম হওয়া ছাড়া বলা শক্ত।

আমি যে পার্থক্যটি আশা করব তা হ'ল দুটি টেবিলের মধ্যবর্তী জিনের আগে অতিরিক্ত ফিল্টারিং। আমার উদাহরণে, আমি আমার টেবিলগুলি পুনরায় ব্যবহার করতে নির্বাচনগুলিতে আপডেটগুলি পরিবর্তন করেছি।

"অপ্টিমাইজেশন" সহ কার্যকরকরণ পরিকল্পনা এখানে চিত্র বর্ণনা লিখুন

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

আপনি পরিষ্কারভাবে একটি ফিল্টার অপারেশন ঘটতে দেখছেন, আমার পরীক্ষার ডেটাতে ফিল্টার আউট হয়েছে এমন কোনও রেকর্ড নেই এবং ফলস্বরূপ যেখানে কোনও উন্নতি হয়নি।

"অপ্টিমাইজেশন" ছাড়াই কার্যকর করার পরিকল্পনা এখানে চিত্র বর্ণনা লিখুন

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

ফিল্টারটি গেছে, যার অর্থ অপ্রয়োজনীয় রেকর্ডগুলি ফিল্টার করার জন্য আমাদের যোগদানের উপর নির্ভর করতে হবে।

অন্যান্য কারণ (গুলি) কোয়েরিটি পরিবর্তনের আরেকটি কারণ / পরিণতি হতে পারে, ক্যোয়ারী পরিবর্তন করার সময় একটি নতুন এক্সিকিউশন প্ল্যান তৈরি করা হয়েছিল, যা দ্রুত হয়। এর উদাহরণ হ'ল ইঞ্জিনটি একটি পৃথক জোড় অপারেটর নির্বাচন করে তবে এটি এই মুহূর্তে অনুমান করা যায়।

সম্পাদনা করুন:

দুটি ক্যোয়ারী প্ল্যান পাওয়ার পরে স্পষ্ট করা:

কোয়েরিটি বড় টেবিল থেকে 550 এম সারিগুলি পড়ছে এবং সেগুলি ছাঁটাই করছে। এখানে চিত্র বর্ণনা লিখুন

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

এসকিএল সার্ভারকে আলাদা সূচক (ক্যোয়ারী পরিকল্পনা) ব্যবহার করা / একটি সূচি যুক্ত করা এটি সমাধান করতে পারে।

তাহলে কেন অনুকূলিত ক্যোয়ারিতে এই একই সমস্যা নেই?

কারণ সন্ধানের পরিবর্তে স্ক্যান সহ একটি আলাদা ক্যোয়ারী পরিকল্পনা ব্যবহৃত হয় plan

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

কোনও সন্ধান না করে, তবে কেবল 4 এম সারি নিয়ে কাজ করতে হবে।

পরবর্তী পার্থক্য

আপডেটের পার্থক্যটিকে উপেক্ষা করে (অনুকূলিত ক্যোয়ারিতে কিছুই আপডেট করা হচ্ছে না) অনুকূলিত ক্যোয়ারিতে একটি হ্যাশ ম্যাচ ব্যবহৃত হয়:

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

নেস্টেড লুপের পরিবর্তে অ-অনুকূলিতকরণে যোগ দিন:

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

একটি টেবিল ছোট এবং অন্যটি বড় হলে নেস্টেড লুপটি সেরা। যেহেতু তারা উভয়ই একই আকারের কাছাকাছি থাকায় আমি যুক্তি দিয়ে বলব যে হ্যাশ ম্যাচ এই ক্ষেত্রে ভাল পছন্দ।

সংক্ষিপ্ত বিবরণ

অপ্টিমাইজড কোয়েরি এখানে চিত্র বর্ণনা লিখুন

অপ্টিমাইজড ক্যোয়ারির পরিকল্পনার সমান্তরালতা রয়েছে, একটি হ্যাশ ম্যাচ জয়েন ব্যবহার করা হয়েছে এবং এর জন্য কম রেসিডুয়াল আইও ফিল্টারিং করা দরকার। এটি মূল মানগুলি মুছে ফেলার জন্য একটি বিটম্যাপ ব্যবহার করে যা কোনও যোগদানের সারি তৈরি করতে পারে না। (এছাড়াও কিছুই আপডেট করা হচ্ছে না)

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

অপ্টিমাইজড কোয়েরিটি উন্নত করতে আপনি কী করতে পারেন?

  • মূল কলাম তালিকায় প্রথম_নাম এবং শেষ নাম রাখাতে সূচকটি পরিবর্তন করা হচ্ছে:

    INDEX IX_largeTableOfPeople_birth_date_first_name_last_name on dbo.largeTableOfPeople (জন্ম_ তারিখ, প্রথম নাম, সর্বশেষ_নাম) অন্তর্ভুক্ত (আইডি)

তবে ফাংশনগুলির ব্যবহার এবং এই টেবিলটি বড় হওয়ার কারণে এটি সর্বোত্তম সমাধান হতে পারে না।

  • উন্নত পরিকল্পনাটি পাওয়ার জন্য পুনরায় সংকলন ব্যবহার করে পরিসংখ্যান আপডেট করা।
  • অনুযায়ী OPTION যোগ করার পদ্ধতি (HASH JOIN, MERGE JOIN)প্রশ্নের
  • ...

পরীক্ষার ডেটা + ক্যোরি ব্যবহার করা হয়েছে

CREATE TABLE #smallTableOfPeople(importantValue int, birthDate datetime2, first_name varchar(50),last_name varchar(50));
CREATE TABLE #largeTableOfPeople(importantValue int, birth_date datetime2, first_name varchar(50),last_name varchar(50));


set nocount on;
DECLARE @i int = 1
WHILE @i <= 1000
BEGIN
insert into #smallTableOfPeople (importantValue,birthDate,first_name,last_name)
VALUES(NULL, dateadd(mi,@i,'2018-01-18 11:05:29.067'),'Frodo','Baggins');

set @i += 1;
END


set nocount on;
DECLARE @j int = 1
WHILE @j <= 20000
BEGIN
insert into #largeTableOfPeople (importantValue,birth_Date,first_name,last_name)
VALUES(@j, dateadd(mi,@j,'2018-01-18 11:05:29.067'),'Frodo','Baggins');

set @j += 1;
END


SET STATISTICS IO, TIME ON;

SELECT  smallTbl.importantValue , largeTbl.importantValue
FROM #smallTableOfPeople smallTbl
JOIN #largeTableOfPeople largeTbl
    ON largeTbl.birth_date = smallTbl.birthDate
    AND DIFFERENCE(RTRIM(LTRIM(smallTbl.last_name)),RTRIM(LTRIM(largeTbl.last_name))) = 4
    AND DIFFERENCE(RTRIM(LTRIM(smallTbl.first_name)),RTRIM(LTRIM(largeTbl.first_name))) = 4
WHERE smallTbl.importantValue IS NULL
-- The following line is "the optimization"
AND LEFT(RTRIM(LTRIM(largeTbl.last_name)), 1) IN ('a','à','á','b','c','d','e','è','é','f','g','h','i','j','k','l','m','n','o','ô','ö','p','q','r','s','t','u','ü','v','w','x','y','z','æ','ä','ø','å');

SELECT  smallTbl.importantValue , largeTbl.importantValue
FROM #smallTableOfPeople smallTbl
JOIN #largeTableOfPeople largeTbl
    ON largeTbl.birth_date = smallTbl.birthDate
    AND DIFFERENCE(RTRIM(LTRIM(smallTbl.last_name)),RTRIM(LTRIM(largeTbl.last_name))) = 4
    AND DIFFERENCE(RTRIM(LTRIM(smallTbl.first_name)),RTRIM(LTRIM(largeTbl.first_name))) = 4
WHERE smallTbl.importantValue IS NULL
-- The following line is "the optimization"
--AND LEFT(RTRIM(LTRIM(largeTbl.last_name)), 1) IN ('a','à','á','b','c','d','e','è','é','f','g','h','i','j','k','l','m','n','o','ô','ö','p','q','r','s','t','u','ü','v','w','x','y','z','æ','ä','ø','å')




drop table #largeTableOfPeople;
drop table #smallTableOfPeople;

8

এটি পরিষ্কার নয় যে দ্বিতীয় ক্যোয়ারী আসলে একটি উন্নতি।

মৃত্যুদণ্ড কার্যকর করার পরিকল্পনায় ক্যোরিটাইমস্ট্যাটস রয়েছে যা প্রশ্নের মধ্যে বর্ণিত চেয়ে অনেক কম নাটকীয় পার্থক্য দেখায়।

ধীর পরিকল্পনার একটি বিচ্ছিন্ন সময় ছিল 257,556 ms(4 মিনিট 17 সেকেন্ড)। 190,992 ms3 টির সমান্তরালতা ডিগ্রি নিয়ে চললেও দ্রুত পরিকল্পনার (3 মিনিট 11 সেকেন্ড) সময় অতিবাহিত হয়েছিল ।

তবুও দ্বিতীয় পরিকল্পনাটি একটি ডাটাবেসে চলছে যেখানে যোগদানের পরে কোনও কাজ করার দরকার ছিল না।

প্রথম পরিকল্পনা

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

দ্বিতীয় পরিকল্পনা

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

সুতরাং অতিরিক্ত সময়টি 3.5 মিলিয়ন সারিগুলি আপডেট করার জন্য প্রয়োজনীয় কাজের দ্বারা ভালভাবে ব্যাখ্যা করা যেতে পারে (এই সারিগুলি সনাক্ত করতে, পৃষ্ঠাটি ল্যাচ করতে, পৃষ্ঠায় আপডেটটি লিখতে এবং লেনদেনের লগ অপ্রয়োজনীয় নয়)

তাহলে এই সত্য পুনরায় উত্পাদন হয় যখন তখন মতো মত তুলনা ব্যাখ্যা যে আপনি শুধু এই ক্ষেত্রে ভাগ্যবান হয়।

37 টি INশর্তযুক্ত ফিল্টারটি কেবল সারণীতে 4,008,334 এর মধ্যে 51 টি সারি অপসারণ করেছে তবে অপটিমাইজার বিবেচনা করে এটি আরও অনেক কিছু সরিয়ে ফেলবে

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

   LEFT(TRIM(largeTbl.last_name), 1) IN ( 'a', 'à', 'á', 'b',
                                          'c', 'd', 'e', 'è',
                                          'é', 'f', 'g', 'h',
                                          'i', 'j', 'k', 'l',
                                          'm', 'n', 'o', 'ô',
                                          'ö', 'p', 'q', 'r',
                                          's', 't', 'u', 'ü',
                                          'v', 'w', 'x', 'y',
                                          'z', 'æ', 'ä', 'ø', 'å' ) 

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

TRIMএসকিউএল সার্ভার ব্যতীত এটিকে বেস কলাম হিস্টোগ্রামের একটি পরিসর ব্যবধানে রূপান্তর করতে সক্ষম করে এবং আরও অনেক সঠিক অনুমান দিতে পারে তবে TRIMএটি কেবল অনুমানের দিকেই আসে।

অনুমানের প্রকৃতি পরিবর্তিত হতে পারে তবে কোনও একক শিকারীর প্রাক্কলনটি LEFT(TRIM(largeTbl.last_name), 1)কিছু পরিস্থিতিতে রয়েছে * ঠিক যেমনটি অনুমান করা যায় table_cardinality/estimated_number_of_distinct_column_values

আমি ঠিক কি পরিস্থিতিতে তা নিশ্চিত নই - ডেটার আকার মনে হয় কোনও অংশ খেলবে। আমি এখানে প্রশস্ত স্থির দৈর্ঘ্যের ডেটাটাইপগুলির সাথে এটি পুনরুত্পাদন করতে সক্ষম হয়েছি তবে এটির চেয়ে আলাদা, উচ্চতর অনুমান varchar(যা সবেমাত্র একটি ফ্ল্যাট 10% অনুমান এবং আনুমানিক 100,000 সারি ব্যবহার করেছে) পেয়েছি । @ সলোমন রুটজকি দেখিয়েছেন যে নিম্ন অনুমানের varchar(100)জন্য যদি স্থানটি অনুসরণযোগ্য স্থানগুলির সাথে প্যাড করা হয় charতবে এটি ব্যবহৃত হয়

INলিস্টে আউট প্রসারিত হয় ORএবং SQL সার্ভার ব্যবহার সূচকীয় backoff 4 predicates বিবেচিত সর্বোচ্চ সঙ্গে। সুতরাং 219.707অনুমানটি নিম্নলিখিত হিসাবে উপস্থিত হয়েছে।

DECLARE @TableCardinality FLOAT = 4008334, 
        @DistinctColumnValueEstimate FLOAT = 34207

DECLARE @NotSelectivity float = 1 - (1/@DistinctColumnValueEstimate)

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