কোন এসকিউএল কোয়েরি দ্রুত? যোগদানের মানদণ্ডে ফিল্টার করুন বা কোথায় ক্লজ?


99

এই 2 টি প্রশ্নের তুলনা করুন। যোগদানের মানদণ্ডে বা এর মধ্যে ফিল্টার স্থাপন করা কি দ্রুতWHERE ? আমি সবসময় অনুভব করেছি যে এটি যোগদানের মানদণ্ডে দ্রুততর কারণ এটি শীঘ্রই সম্ভাব্য মুহুর্তে ফলাফল সেটটিকে হ্রাস করে, তবে আমি নিশ্চিতভাবে জানি না।

আমি দেখতে কিছু পরীক্ষা তৈরি করতে যাচ্ছি, তবে আমি মতামতও পেতে চেয়েছিলাম যার বিষয়ে পড়ার বিষয়টি আরও পরিষ্কার হবে।

প্রশ্ন ঘ

SELECT      *
FROM        TableA a
INNER JOIN  TableXRef x
        ON  a.ID = x.TableAID
INNER JOIN  TableB b
        ON  x.TableBID = b.ID
WHERE       a.ID = 1            /* <-- Filter here? */

প্রশ্ন 2

SELECT      *
FROM        TableA a
INNER JOIN  TableXRef x
        ON  a.ID = x.TableAID
        AND a.ID = 1            /* <-- Or filter here? */
INNER JOIN  TableB b
        ON  x.TableBID = b.ID

সম্পাদনা

আমি কিছু পরীক্ষা চালিয়েছি এবং ফলাফলগুলি দেখায় যে এটি আসলে খুব কাছাকাছি, তবে WHEREক্লজটি আসলে কিছুটা দ্রুত! =)

আমি সম্পূর্ণরূপে সম্মত হই যে এটির উপর ফিল্টার প্রয়োগ করা আরও বোধগম্য WHERE অর্থবোধ করে, আমি পারফরম্যান্সের প্রভাব সম্পর্কে কেবল কৌতূহলী ছিলাম।

বিপজ্জনক সময় যেখানে ক্রিটরিয়া : 143016
মিমি সময়সীমার সাথে সময় কাটাও: ক্রিটরিয়া 143256 এমএস

পরীক্ষা

SET NOCOUNT ON;

DECLARE @num    INT,
        @iter   INT

SELECT  @num    = 1000, -- Number of records in TableA and TableB, the cross table is populated with a CROSS JOIN from A to B
        @iter   = 1000  -- Number of select iterations to perform

DECLARE @a TABLE (
        id INT
)

DECLARE @b TABLE (
        id INT
)

DECLARE @x TABLE (
        aid INT,
        bid INT
)

DECLARE @num_curr INT
SELECT  @num_curr = 1
        
WHILE (@num_curr <= @num)
BEGIN
    INSERT @a (id) SELECT @num_curr
    INSERT @b (id) SELECT @num_curr
    
    SELECT @num_curr = @num_curr + 1
END

INSERT      @x (aid, bid)
SELECT      a.id,
            b.id
FROM        @a a
CROSS JOIN  @b b

/*
    TEST
*/
DECLARE @begin_where    DATETIME,
        @end_where      DATETIME,
        @count_where    INT,
        @begin_join     DATETIME,
        @end_join       DATETIME,
        @count_join     INT,
        @curr           INT,
        @aid            INT

DECLARE @temp TABLE (
        curr    INT,
        aid     INT,
        bid     INT
)

DELETE FROM @temp

SELECT  @curr   = 0,
        @aid    = 50

SELECT  @begin_where = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
    INSERT      @temp (curr, aid, bid)
    SELECT      @curr,
                aid,
                bid
    FROM        @a a
    INNER JOIN  @x x
            ON  a.id = x.aid
    INNER JOIN  @b b
            ON  x.bid = b.id
    WHERE       a.id = @aid
        
    SELECT @curr = @curr + 1
END
SELECT  @end_where = CURRENT_TIMESTAMP

SELECT  @count_where = COUNT(1) FROM @temp
DELETE FROM @temp

SELECT  @curr = 0
SELECT  @begin_join = CURRENT_TIMESTAMP
WHILE (@curr < @iter)
BEGIN
    INSERT      @temp (curr, aid, bid)
    SELECT      @curr,
                aid,
                bid
    FROM        @a a
    INNER JOIN  @x x
            ON  a.id = x.aid
            AND a.id = @aid
    INNER JOIN  @b b
            ON  x.bid = b.id
    
    SELECT @curr = @curr + 1
END
SELECT  @end_join = CURRENT_TIMESTAMP

SELECT  @count_join = COUNT(1) FROM @temp
DELETE FROM @temp

SELECT  @count_where AS count_where,
        @count_join AS count_join,
        DATEDIFF(millisecond, @begin_where, @end_where) AS elapsed_where,
        DATEDIFF(millisecond, @begin_join, @end_join) AS elapsed_join

10
ডেটার উপর নির্ভর করে WHOE বনাম JOIN মানদণ্ড বিভিন্ন ফলাফলের ফলাফল দিতে পারে।
ওএমজি পনিজ

4
@ ওএমজি পনিগুলি খুব সত্য, তবে অনেক সময় এটি ঠিক হয় না।
জন এরিকসন

4
আমি পার্থক্যটিকে 5% পার্থক্য হিসাবে কল করব না - তারা একই। এটি কেবল এলোমেলো নয় তা নিশ্চিত করার জন্য আপনি 2 %% পার্থক্যের জন্য 1000 বার পরীক্ষা চালানোর জন্য তাত্পর্যটি চান।
টমটম

যোগদানের পূর্বে ডেটা ফিল্টার করার সুবিধাটি হ'ল এটি যদি x.ID হয় তবে আপনি একটি এআইডির চেয়ে উন্নতি দেখতে পাবে
মাইকটি

উত্তর:


66

পারফরম্যান্স অনুসারে, তারা একই (এবং একই পরিকল্পনা তৈরি করে)

যৌক্তিকভাবে, আপনি যদি INNER JOINএকটি দিয়ে প্রতিস্থাপন করেন তবে আপনার অপারেশনটি এখনও বুদ্ধিমান হওয়া উচিত LEFT JOIN

আপনার ক্ষেত্রে এটি দেখতে এরকম হবে:

SELECT  *
FROM    TableA a
LEFT JOIN
        TableXRef x
ON      x.TableAID = a.ID
        AND a.ID = 1
LEFT JOIN
        TableB b
ON      x.TableBID = b.ID

অথবা এটা:

SELECT  *
FROM    TableA a
LEFT JOIN
        TableXRef x
ON      x.TableAID = a.ID
LEFT JOIN
        TableB b
ON      b.id = x.TableBID
WHERE   a.id = 1

প্রাক্তন ক্যোয়ারীটি a.idব্যতীত অন্য কোনও আসল ম্যাচ ফেরত দেবে না 1, সুতরাং পরবর্তী সিনট্যাক্স (সহ WHERE) যুক্তিযুক্তভাবে আরও সুসংগত।


আমি যখন সেটগুলি আঁকলাম তখন বুঝতে পারছিলাম যে দ্বিতীয় কেসটি আরও সুসংগত। পূর্ববর্তী ক্যোয়ারিতে, সীমাবদ্ধতা a.id = 1কেবল ছেদটির জন্য প্রযোজ্য, ছেদটি বাদ দিয়ে বাম অংশটি নয়।
ফিথবিল্ডার

4
প্রথম উদাহরণে সারি থাকতে পারে যেখানে a.id != 1, অন্যটিতে কেবল সারি থাকবে a.id = 1
ফিথবিল্ডার

4
আপনার ভাষা অস্পষ্ট। "যৌক্তিকভাবে, আপনার যদি এমন অপারেশন করা উচিত যা এখনও বুদ্ধিমান হয় তবে ..." এবং "যুক্তিসঙ্গতভাবে আরও সুসংগত" যদি তা বোঝা যায় না। আপনি দয়া করে পুনরায় প্রতিস্থাপন করতে পারেন?
ফিলিপ্সি

24

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

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


সুতরাং অভ্যন্তরীণ যোগে এটি প্রথমে ফিল্টারটি গণনা করে তারপরে অন্য টেবিলের সাথে ফিল্টারটির আউটপুটে যোগ দেয় বা এটি প্রথমে দুটি টেবিলগুলিতে যোগদান করে এবং পরে ফিল্টারটি প্রয়োগ করে?
আশ্বিন

@ রেমাস রুসানু - আপনি কী দয়া করে বহিরাগত যোগদানের ক্ষেত্রে শব্দার্থবিজ্ঞান কীভাবে পরিবর্তিত হয় সে সম্পর্কে বিস্তারিত বলতে পারেন? আমি ফিল্টারটির অবস্থানের ভিত্তিতে বিভিন্ন ফলাফল পেয়েছি, তবে কেন বুঝতে পারি না
অনন্ত

4
@ বাহ্যিক যোগদানের সাথে অনানথ আপনি যুক্ত টেবিলের সমস্ত কলামের জন্য NULs পাবেন যেখানে জওআইএন শর্তটি মেলে না। ফিল্টারগুলি NUL সন্তুষ্ট করবে না এবং সারিগুলি সরিয়ে ফেলবে, আউটআর জয়েনটিকে একটি INNER join এ রূপান্তর করবে।
রেমাস রুসানু

@ অ্যান্থ আমি আপনার মন্তব্যের ভিত্তিতে আমার প্রয়োজনীয় অপটিমাইজেশন অর্জন করেছি। আমার পরিবর্তনটি WHERE x.TableAID = a.ID বা x.TableAID থেকে শুরু হয়েছে x x.TableAID = a.ID. একটি OUTER যোগে ফিল্টারটির অবস্থান পরিবর্তন করে সংযোজকটিকে ফিল্টার জানুন তারপরে যোগদানের পরে ফিল্টার করুন তার পরিবর্তে যোগদান করুন let এটি সেই কলামে সূচকটি ব্যবহার করতে সক্ষম হয়েছিল কারণ এটি নুলের সাথে মেলেনি। প্রশ্নের প্রতিক্রিয়া 61 সেকেন্ড থেকে 2 সেকেন্ডে পরিবর্তিত হয়েছে।
বেন গ্রিপকা

10

যতদূর দুটি পদ্ধতি যায়।

  • যোগদান / সারণী সারণিতে যোগদানের জন্য
  • ফিল্টারিং ফলাফলের জন্য কোথায়

আপনি এগুলিকে আলাদাভাবে ব্যবহার করতে পারবেন তা সর্বদা আমার কাছে দুর্গন্ধযুক্ত বলে মনে হয়।

কোনও সমস্যা হলে পারফরম্যান্সের সাথে ডিল করুন। তারপরে আপনি এই জাতীয় "অপটিমাইজেশন" সন্ধান করতে পারেন।


2

যে কোনও কোয়েরি অপ্টিমাইজার সহ এক শতাংশ .... এগুলি অভিন্ন।


আমি নিশ্চিত যে কোনও বাস্তব কাজের চাপ সহ, তারা অভিন্ন নয়। আপনার যদি প্রায় ডেটা না থাকে, তবে প্রশ্নটি মূল্যহীন।
eKek0

4
এটি বাস্তব কাজের চাপের অধীনে পরীক্ষা করে দেখুন। মূলত - যদি তারা একই বাস্তবায়ন পরিকল্পনা উত্পন্ন করে তবে তারা ... পারফরম্যান্সে অভিন্ন। কমপক্ষে সাধারণ / সাধারণ ক্ষেত্রে (যেমন 14 টি টেবিলগুলিতে যোগদানকারী নয়) আমি নিশ্চিত যে তারা অভিন্ন;)
টমটম

1

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

# explain analyze select e.* from event e join result r on e.id = r.event_id and r.team_2_score=24;

                                                  QUERY PLAN                                                   
---------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=27.09..38.22 rows=7 width=899) (actual time=0.045..0.047 rows=1 loops=1)
   Hash Cond: (e.id = r.event_id)
   ->  Seq Scan on event e  (cost=0.00..10.80 rows=80 width=899) (actual time=0.009..0.010 rows=2 loops=1)
   ->  Hash  (cost=27.00..27.00 rows=7 width=8) (actual time=0.017..0.017 rows=1 loops=1)
         Buckets: 1024  Batches: 1  Memory Usage: 9kB
         ->  Seq Scan on result r  (cost=0.00..27.00 rows=7 width=8) (actual time=0.006..0.008 rows=1 loops=1)
               Filter: (team_2_score = 24)
               Rows Removed by Filter: 1
 Planning time: 0.182 ms
 Execution time: 0.101 ms
(10 rows)

# explain analyze select e.* from event e join result r on e.id = r.event_id where r.team_2_score=24;
                                                  QUERY PLAN                                                   
---------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=27.09..38.22 rows=7 width=899) (actual time=0.027..0.029 rows=1 loops=1)
   Hash Cond: (e.id = r.event_id)
   ->  Seq Scan on event e  (cost=0.00..10.80 rows=80 width=899) (actual time=0.010..0.011 rows=2 loops=1)
   ->  Hash  (cost=27.00..27.00 rows=7 width=8) (actual time=0.010..0.010 rows=1 loops=1)
         Buckets: 1024  Batches: 1  Memory Usage: 9kB
         ->  Seq Scan on result r  (cost=0.00..27.00 rows=7 width=8) (actual time=0.006..0.007 rows=1 loops=1)
               Filter: (team_2_score = 24)
               Rows Removed by Filter: 1
 Planning time: 0.140 ms
 Execution time: 0.058 ms
(10 rows)

তাদের উভয়ের একই ন্যূনতম এবং সর্বোচ্চ ব্যয়ের পাশাপাশি একই ক্যোয়ারী পরিকল্পনা রয়েছে plan এছাড়াও, লক্ষ্য করুন যে এমনকি শীর্ষ ক্যোয়ারিতেও টিম_স্কোর_2 একটি 'ফিল্টার' হিসাবে প্রয়োগ হয়।


0

এই যোগদানের স্থানটি কার্য সম্পাদনের সিদ্ধান্ত নেওয়ার কারণ হিসাবে সত্যই অসম্ভাব্য। আমি tsql এর জন্য মৃত্যুদন্ড কার্যকর করার পরিকল্পনার সাথে নিবিড়ভাবে পরিচিত নই, তবে সম্ভবত তারা অনুরূপ পরিকল্পনায় স্বয়ংক্রিয়ভাবে অনুকূলিত হবে।


0

বিধি # 0: কিছু মানদণ্ড চালান এবং দেখুন! আসলে কোনটি দ্রুত হবে তা বলার একমাত্র উপায় হ'ল চেষ্টা করা। এসকিউএল প্রোফাইলার ব্যবহার করে এই ধরণের মানদণ্ড সম্পাদন করা খুব সহজ।

এছাড়াও, কোন যোগদানের সাথে এবং একটি পৃথক দফায় কী পার্থক্য প্রকাশিত হয়েছে তা দেখার জন্য লিখিত ক্যোয়ারির কার্যকরকরণ পরিকল্পনা পরীক্ষা করুন।

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


তবে কেবল অভ্যন্তরীণ যোগদানের জন্য। যোগদানের ফলাফলের ফলাফল খুব আলাদা হবে।
এইচএলজিইএম

অবশ্যই. ভাগ্যক্রমে, সরবরাহিত উদাহরণটি অভ্যন্তরীণ যোগদানগুলিতে ব্যবহার করে।
ডিভে

4
দুর্ভাগ্যক্রমে প্রশ্নটি অন্তর্ভুক্ত হয়ে নয়, যোগদানের বিষয়ে।
পল

হ্যাঁ ডেভিড, প্রশ্নটি যোগ দেওয়ার বিষয়ে। প্রশ্নটিকে সমর্থনকারী নমুনাটি অভ্যন্তরীণ যোগদানগুলিতে ব্যবহার করতে ঘটে।
পল

0

এটা কি দ্রুত? চেষ্টা করে দেখুন।

কোনটি পড়া সহজ? আমার কাছে প্রথমটি আরও "সঠিক" দেখাচ্ছে, কারণ সরানো শর্তটি যোগদানের সাথে আসলে কিছুই করার নেই।


0

আমি অনুমান করি যে এটি প্রথম, কারণ এটি ডেটার উপরে আরও নির্দিষ্ট ফিল্টার তৈরি করে। তবে আপনার কোনও অপ্টিমাইজেশনের মতোই এক্সিকিউশন প্ল্যানটিও দেখতে হবে, কারণ এটি ডেটা, সার্ভার হার্ডওয়্যার ইত্যাদির আকারের তুলনায় খুব আলাদা হতে পারে can

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