যদি এম্বেড করা স্টেটমেন্টের চেয়ে বেশি সময় নেয় তবে


35

আমি যখন নিম্নলিখিত কোডটি চালিত করি তখন এটি 22.5 মিনিট সময় নেয় এবং 106 মিলিয়ন পড়ে reads যাইহোক, আমি যদি নিজেই কেবল অভ্যন্তরীণ নির্বাচনের বিবৃতিটি চালিত করি তবে এটি কেবল 15 সেকেন্ড সময় নেয় এবং 264k পড়ে। পার্শ্ব নোট হিসাবে, নির্বাচন করা ক্যোয়ারী কোনও রেকর্ড দেয় না।

কোনও ধারণা কেন এটি IF EXISTSএত দীর্ঘ সময় চালায় এবং আরও অনেকগুলি পড়তে পারে? আমি নির্বাচন করার জন্য নির্বাচিত বিবৃতিটিও পরিবর্তন SELECT TOP 1 [dlc].[id]করেছি এবং আমি এটি 2 মিনিটের পরে হত্যা করি।

একটি অস্থায়ী ফিক্স হিসাবে আমি এটি একটি গণনা (*) করতে পরিবর্তন করেছি এবং ভেরিয়েবলের জন্য সেই মানটি নির্ধারণ করি @cnt। তারপরে এটি একটি IF 0 <> @cntবিবৃতি দেয়। তবে আমি ভেবেছিলাম EXISTSআরও ভাল হবে, কারণ যদি নির্বাচিত বিবৃতিতে রেকর্ডগুলি ফিরে আসে তবে এটি কমপক্ষে একটি রেকর্ড পাওয়া গেলে এটি স্ক্যান করা / সন্ধান করা বন্ধ করে দেবে, যেখানে count(*)পূর্ণ বিবরণটি সম্পূর্ণ করবে। আমি কী মিস করছি?

IF EXISTS
   (SELECT [dlc].[ID]
   FROM TableDLC [dlc]
   JOIN TableD [d]
   ON [d].[ID] = [dlc].[ID]
   JOIN TableC [c]
   ON [c].[ID] = [d].[ID2]
   WHERE [c].[Name] <> [dlc].[Name])
BEGIN
   <do something>
END

4
সারি লক্ষ্য সমস্যা এড়ানোর জন্য, অন্য ধারণা (অনির্ধারিত, মনে রাখবেন!) হতে পারে বিপরীতটি চেষ্টা করে দেখুন - IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
অ্যারন বারট্র্যান্ড

উত্তর:


32

কোনও ধারণা কেন এটি IF EXISTSএত দীর্ঘ সময় চালায় এবং আরও অনেকগুলি পড়তে পারে? আমি নির্বাচন করার জন্য নির্বাচিত বিবৃতিটিও পরিবর্তন SELECT TOP 1 [dlc].[id]করেছি এবং আমি এটি 2 মিনিটের পরে হত্যা করি।

আমি এই সম্পর্কিত প্রশ্নের আমার উত্তরে যেমন ব্যাখ্যা করেছি:

কীভাবে (এবং কেন) শীর্ষস্থানীয় কার্য সম্পাদন পরিকল্পনাকে প্রভাবিত করে?

ব্যবহার করে EXISTSএকটি সারি লক্ষ্য প্রবর্তিত হয়, যেখানে অপ্টিমাইজারটি প্রথম সারিতে দ্রুত চিহ্নিত করার লক্ষ্যে একটি কার্যকরকরণ পরিকল্পনা তৈরি করে। এটি করার ফলে এটি ধরে নেওয়া হয় যে ডেটা সমানভাবে বিতরণ করা হয়েছে। উদাহরণস্বরূপ, যদি পরিসংখ্যানগুলি দেখায় 100,000 সারিগুলিতে 100 টি প্রত্যাশিত ম্যাচ রয়েছে তবে এটি ধরে নেওয়া হবে যে প্রথম ম্যাচটি খুঁজে পেতে এটি কেবল 1000 টি সারি পড়তে হবে।

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

অস্থায়ী স্থির হিসাবে আমি এটি একটি কাউন্ট (*) করতে পরিবর্তন করেছি এবং সেই মানটি একটি ভেরিয়েবলের জন্য বরাদ্দ করি

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

আপনি যদি এসকিউএল সার্ভার ২০০৮ আর 2 চালিয়ে যাচ্ছেন বা সারণী লক্ষ্য ছাড়াই একটি কার্যকরকরণ পরিকল্পনা পেতে আপনি সাধারণত ডকুমেন্টেড এবং সমর্থিত ট্রেস পতাকা 4138 ব্যবহার করতে পারেন । এই পতাকাটি সমর্থিত ইঙ্গিতটি ব্যবহার করেও নির্দিষ্ট করা যেতে পারে OPTION (QUERYTRACEON 4138), তবে সচেতন থাকুন এটির জন্য রানটাইম সিসাদমিন অনুমতি প্রয়োজন, যদি না কোনও পরিকল্পনা গাইড ব্যবহার না করা হয়।

দুর্ভাগ্যবশত

উপরের কোনটি IF EXISTSশর্তাধীন বিবৃতি সহ কার্যকর নয়। এটি কেবল নিয়মিত ডিএমএলে প্রযোজ্য। এটি আপনার চেষ্টা করা বিকল্প সূত্রের সাথে কাজ করবেSELECT TOP (1) । এটি ব্যবহারের চেয়ে ভাল হতে পারে COUNT(*), যা পূর্বে উল্লিখিত হিসাবে সমস্ত যোগ্য সারি গণনা করতে হবে।

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

DECLARE @Exists bit;

SELECT @Exists =
    CASE
        WHEN EXISTS
        (
            SELECT [dlc].[ID]
            FROM TableDLC [dlc]
            JOIN TableD [d]
            ON [d].[ID] = [dlc].[ID]
            JOIN TableC [c]
            ON [c].[ID] = [d].[ID2]
            WHERE [c].[Name] <> [dlc].[Name]
        )
        THEN CONVERT(bit, 1)
        ELSE CONVERT(bit, 0)
    END
OPTION (QUERYTRACEON 4138);

IF @Exists = 1
BEGIN
    ...
END;

আপনি সরবরাহ করেছেন এমন সর্বোত্তম উদাহরণটি 3.75 মিনিটের মধ্যে ছড়িয়ে পড়ে এবং 46 মিটার পঠন সম্পাদন করে। সুতরাং, আমার মূল ক্যোয়ারীর চেয়ে দ্রুততর, আমি মনে করি এই ক্ষেত্রে আমি @ cnt = গণনা (*) এর সাথে থাকব এবং তার পরে ভেরিয়েবলটি মূল্যায়ন করব। বিশেষত যেহেতু 99% সময় এটি চালায় তাতে কিছুই থাকবে না। আপনার এবং রবের উত্তরের উপর ভিত্তি করে মনে হচ্ছে যে আপনি যদি কিছু ধরণের ফলাফল আশা করেন এবং ফলাফলটি আপনার ডেটাতে সমানভাবে বিতরণ করা হয় তবেই অস্তিত্বগুলি কেবলমাত্র ভাল good
ক্রিস উডস

3
@ ক্রিসউডস: আপনি বলেছিলেন "বিশেষত যেহেতু 99% এই সময়টি চালিত হয় তাতে কিছুই থাকবে না"। এটি বেশিরভাগ ক্ষেত্রে গ্যারান্টি দেয় যে একটির সারি লক্ষ্যটি একটি খারাপ ধারণা, যেহেতু আপনি আশা করেন যে সেখানে সাধারণত কোনও সারি থাকবে না এবং কোনও কিছুই নেই তা খুঁজে পাওয়ার জন্য সমস্ত কিছু স্ক্যান করতে হবে। আপনি যদি কিছু চালাক সূচক যোগ করতে না পারেন তবে COUNT (*) এর সাথে লেগে থাকুন।
রস প্রেসার

25

যেহেতু অস্তিত্ব কেবলমাত্র একটি একক সারি সন্ধান করতে পারে, এটি একটির একটি সারি লক্ষ্য ব্যবহার করবে। এটি কখনও কখনও কখনও কখনও কখনও কখনও কখনও কম-আদর্শ-পরিকল্পনা তৈরি করতে পারে। যদি আপনি আশা করেন যে এটি আপনার জন্য এটির মতো হয়ে থাকে তবে এর ফলাফলের সাথে একটি ভেরিয়েবলকে বসান COUNT(*)এবং তারপরে সেই পরিবর্তনশীলটি 0 এর বেশি হয় কিনা তা পরীক্ষা করুন।

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

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