নেস্টেড লুপগুলিতে ধীরে ধীরে চলমান এমন কোনও কোয়েরি কীভাবে অনুকূল করবেন (অভ্যন্তরীণ যোগ দিন)


39

টি এল; ডিআর

যেহেতু এই প্রশ্নটিতে মতামত পাওয়া যায়, তাই আমি এখানে সংক্ষিপ্ত করে রাখি যাতে নতুনদের ইতিহাস ভোগ করতে না হয়:

JOIN table t ON t.member = @value1 OR t.member = @value2 -- this is slow as hell
JOIN table t ON t.member = COALESCE(@value1, @value2)    -- this is blazing fast
-- Note that here if @value1 has a value, @value2 is NULL, and vice versa

আমি বুঝতে পারি এটি সবার সমস্যা নাও হতে পারে, তবে ওএন ক্লজের সংবেদনশীলতা তুলে ধরে এটি আপনাকে সঠিক দিকে তাকাতে সহায়তা করতে পারে। যে কোনও ক্ষেত্রে আসল পাঠটি ভবিষ্যতের নৃতত্ত্ববিদদের জন্য এখানে রয়েছে:

মূল পাঠ্য

নিম্নলিখিত সাধারণ প্রশ্নটি বিবেচনা করুন (কেবলমাত্র 3 টি টেবিল জড়িত)

    SELECT

        l.sku_id AS ProductId,
        l.is_primary AS IsPrimary,
        v1.category_name AS Category1,
        v2.category_name AS Category2,
        v3.category_name AS Category3,
        v4.category_name AS Category4,
        v5.category_name AS Category5

    FROM category c4
    JOIN category_voc v4 ON v4.category_id = c4.category_id and v4.language_code = 'en'

    JOIN category c3 ON c3.category_id = c4.parent_category_id
    JOIN category_voc v3 ON v3.category_id = c3.category_id and v3.language_code = 'en'

    JOIN category c2 ON c2.category_id = c3.category_id
    JOIN category_voc v2 ON v2.category_id = c2.category_id and v2.language_code = 'en'

    JOIN category c1 ON c1.category_id = c2.parent_category_id
    JOIN category_voc v1 ON v1.category_id = c1.category_id and v1.language_code = 'en'

    LEFT OUTER JOIN category c5 ON c5.parent_category_id = c4.category_id
    LEFT OUTER JOIN category_voc v5 ON v5.category_id = c5.category_id and v5.language_code = @lang

    JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
    (
        l.category_id = c4.category_id OR
        l.category_id = c5.category_id
    )

    WHERE c4.[level] = 4 AND c4.version_id = 5

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

মৃত্যুদন্ড কার্যকর করার সময়, আমি নিম্নলিখিত প্রকৃত বাস্তবায়ন পরিকল্পনাটি পাই:

প্রকৃত বাস্তবায়ন পরিকল্পনা

আপনি দেখতে পাচ্ছেন, প্রায় 90% সময় নেস্টেড লুপগুলিতে (অভ্যন্তরীণ যোগ দিন) ব্যয় হয়। এই নেস্টেড লুপগুলি সম্পর্কে অতিরিক্ত তথ্য এখানে:

নেস্টেড লুপস (অভ্যন্তরীণ যোগদান)

নোট করুন যে টেবিলের নামগুলি হুবহু মিলছে না কারণ আমি পাঠযোগ্যতার জন্য ক্যোরি সারণীর নামগুলি সম্পাদনা করেছি তবে এটি মিলিয়ে নেওয়া বেশ সহজ (বিজ্ঞাপন_াল্ট_ক্যাটরি = বিভাগ)। এই ক্যোয়ারীটি অনুকূল করার কোনও উপায় আছে কি? আরও মনে রাখবেন যে উত্পাদনে, টেম্প টেবিল # আইডির অস্তিত্ব নেই, এটি একই 10'000 আইডির একটি সারণী মূল্যবান প্যারামিটারটি সঞ্চিত পদ্ধতিতে প্রেরণ করে।

অতিরিক্ত তথ্য:

  • বিভাগ_আইডি এবং প্যারেন্ট_ক্যাটগরী_আইডিতে বিভাগ সূচকগুলি
  • বিভাগ_ভ, বিভাগ_কোডে বিভাগ_ভোক সূচক
  • বিভাগ_লিঙ্ক সূচক স্কু_আইডি, বিভাগ_আইডিতে

সম্পাদনা (সমাধান)

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

JOIN category_link l on l.sku_id IN (SELECT value FROM @p1) AND l.category_id = COALESCE(c5.category_id, c4.category_id)

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


আমাদের কোয়েরি প্ল্যানের বাকি অংশগুলি দেখতে হবে।
আরবেরি ইয়ং

কেবলমাত্র একটি মন্তব্য: সেই সাথে অনেক নির্ভরশীল কার্ডিনালিটির অনুমানের ত্রুটির সাথে যোগ দেয়। প্রায়শই, ক্যোরিয়াল পারফরম্যান্স কার্ডিনালিটি অবমূল্যায়নের দ্বারা লাইনচ্যুত হয়।
usr ডিরেক্টরির

কার্যকর করার পরিকল্পনা কি সূচকগুলির জন্য পরামর্শ দেয়? এছাড়াও, ভুলে যাবেন না যে আপনি নিজের অস্থায়ী টেবিলগুলিতে প্রাথমিক কী এবং

@ রবারি যদি বর্তমান সমাধানগুলি চেষ্টা করার পরেও আমার কিছু না পাওয়া যায় তবে আমি এই প্রশ্নের উন্নতি করব

1
কোনও ইউনিয়নের সাথে ক্যোয়ারীটি অনুলিপি করা এবং ওআর

উত্তর:


17

কোডটির এই অংশে সমস্যাটি উপস্থিত বলে মনে হচ্ছে:

JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
(
    l.category_id = c4.category_id OR
    l.category_id = c5.category_id
)

orযোগদানের পরিস্থিতিতে সর্বদা সন্দেহজনক। একটি পরামর্শ হ'ল এটিকে দুটি যোগে বিভক্ত করা:

JOIN category_link l1 on l1.sku_id in (SELECT value FROM #Ids) and l1.category_id = cr.category_id
left outer join
category_link l1 on l2.sku_id in (SELECT value FROM #Ids) and l2.category_id = cr.category_id

এরপরে এটি পরিচালনা করতে আপনাকে বাকী বাক্যটি পরিবর্তন করতে হবে। । । অনুচ্ছেদে coalesce(l1.sku_id, l2.sku_id)উদাহরণস্বরূপ select


ফিল্টারিং সেই নির্দিষ্ট করা হচ্ছে পরিমাণ যোগদানের সঙ্গে, আমিও পরিবর্তন পরীক্ষা চাই JOINএকটি থেকে CROSS APPLYসঙ্গে INএকটি ওভার সুইচিং EXISTSমধ্যে APPLYএর WHEREদফা।

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

3
আমি এই উত্তরটি গ্রহণ করছি কারণ এটিই প্রথম উত্তর যা আমাকে সমস্যার দিকে নির্দেশ করেছিল। প্রস্তাবিত সমাধানটি মূল কোডের চেয়ে অত্যন্ত ধীর, ধীর। যাইহোক, ওআর ক্লজটি ইস্যু ছিল তা জেনেও কেবল কৌশলটির বদলে এটি প্রতিস্থাপন করা হয়েছিল ON l.category_id = ISNULL(c5.category_id, c4.category_id
লুইস ফেরারাও

1
@ লুইসফেরওও । । অতিরিক্ত তথ্যের জন্য আপনাকে ধন্যবাদ। এটি জেনে রাখা কার্যকর যে coalesce()অপ্টিমাইজারটিকে সঠিক দিকে ঠেলে দেয়।
গর্ডন লিনফ

9

অন্য একজন ব্যবহারকারী যেমন উল্লেখ করেছেন, এই যোগদানের কারণ সম্ভবত:

JOIN category_link l on l.sku_id IN (SELECT value FROM #Ids) AND
(
    l.category_id = c4.category_id OR
    l.category_id = c5.category_id
)

এগুলি একাধিক যোগদানের বিভক্ত করার পাশাপাশি, আপনিও চেষ্টা করতে পারেন CROSS APPLY

CROSS APPLY (
    SELECT [some column(s)]
    FROM category_link x
    WHERE EXISTS(SELECT value FROM #Ids WHERE value = x.sku_id)
    AND (x.category_id = c4.category_id OR x.category_id = c5.category_id)        
) l

উপরের এমএসডিএন লিঙ্ক থেকে:

টেবিল-মূল্যযুক্ত ফাংশন ডান ইনপুট হিসাবে কাজ করে এবং বাইরের সারণী এক্সপ্রেশনটি বাম ইনপুট হিসাবে কাজ করে। বাম ইনপুট থেকে প্রতিটি সারির জন্য ডান ইনপুট মূল্যায়ন করা হয় এবং উত্পাদিত সারিগুলি চূড়ান্ত আউটপুটটির জন্য একত্রিত করা হয়

মূলত, APPLYএমন একটি সাবকোয়ারির মতো যা প্রথমে ডানদিকে রেকর্ডগুলি ফিল্টার করে এবং তারপরে সেগুলি আপনার বাকী বাক্সে প্রয়োগ করে।

এটি কী এবং কখন এটি ব্যবহার করবেন তা ব্যাখ্যা করার জন্য এই নিবন্ধটি খুব ভাল কাজ করেছে: http://explainextended.com/2009/07/16/inner-join-vs-cross-apply/

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

থাম্বের একটি সাধারণ নিয়ম হিসাবে, যদি আমি নিজেকে অনেকগুলি শর্তাধীন বিবৃতি দিয়ে কোনও টেবিলে যোগদান করতে দেখি তবে আমি ঝুঁকির দিকে ঝুঁকছি APPLY

এছাড়াও একটি মজাদার নোট: OUTER APPLYএকটির মতো কাজ করবেLEFT JOIN

এছাড়াও, দয়া করে আমার পছন্দটি ব্যবহার EXISTSকরার চেয়ে নোট করুন ININসাবকিউরিতে কাজ করার সময়, মনে রাখবেন যে এটি আপনার মানটি সন্ধান করার পরেও এটি পুরো ফলাফল সেটটি ফিরিয়ে দেবে। সঙ্গে EXISTS, যদিও, এটা subquery তাত্ক্ষণিক এটা একটি ম্যাচ খুঁজে বের করে বন্ধ করে দেব।


আমি এই সমাধানটি পুরোপুরি পরীক্ষা করেছি। আপনি যেমনটি লিখেছেন, এটি বেশ ধীর গতির তবে আপনি আপনার বার্তাটি শুরু করেছিলেন সেই পরামর্শটি প্রয়োগ করতে ভুলে গেছেন। আইএন ক্লজটি AND x.cat = c4.cat OR x.cat = c5.catদ্বারা প্রতিস্থাপন x.cat = ISNULL(c5.cat, c4.cat)এবং অব্যাহতি এটিকে দ্বিতীয় দ্রুত সমাধান হিসাবে তৈরি করেছে এবং এটি একটি উত্সাহের যোগ্য, কারণ এটি বেশ তথ্যপূর্ণ।
লুইস ফেররাও

ধন্যবাদ। IN লাইনটি আসলে সেখানে থাকার কথা ছিল না (IN ব্যবহার করা বা ওআর সাথে থাকা সম্পর্কে সিদ্ধান্ত নিতে পারে না), আমি এটি সরিয়ে ফেলব।
ভালভেরিজ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.