স্বতন্ত্র অনুসন্ধানগুলি 10 মিমি চালিত হয়, ইউনিয়ন সমস্ত দিয়ে তারা 290ms + (7.7M রেকর্ড মাইএসকিউএল ডিবি) নিচ্ছে। কীভাবে অপ্টিমাইজ করবেন?


9

আমার কাছে একটি টেবিল রয়েছে যা শিক্ষকদের জন্য উপলব্ধ অ্যাপয়েন্টমেন্ট সঞ্চয় করে রাখে, দুই ধরণের সন্নিবেশকে অনুমতি দেয়:

  1. প্রতি ঘণ্টার ভিত্তিতে : শিক্ষক প্রতি দিন সীমাহীন স্লট যোগ করার সম্পূর্ণ স্বাধীনতার সাথে (যতক্ষণ না স্লট ওভারল্যাপ হয় না): 15 / এপ্রিল একজন শিক্ষকের 10:00, 11:00, 12:00 এবং 16:00 এ স্লট থাকতে পারে । একটি নির্দিষ্ট শিক্ষক সময় / স্লট চয়ন করার পরে একজন ব্যক্তির পরিবেশন করা হয়।

  2. সময়কাল / ব্যাপ্তি : 15 / এপ্রিল অপর একজন শিক্ষক 10:00 থেকে 12:00 এবং তারপরে 14:00 থেকে 18:00 পর্যন্ত কাজ করতে পারে। একজন ব্যক্তির আগমনের আদেশ দ্বারা পরিবেশন করা হয়, সুতরাং যদি কোনও শিক্ষক 10:00 থেকে 12:00 অবধি কাজ করেন তবে এই সময়ের মধ্যে আগত সমস্ত ব্যক্তি আগমনের আদেশে উপস্থিত হবে (স্থানীয় সারি)।

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

বর্তমান টেবিল কাঠামো

CREATE TABLE `teacher_slots` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `teacher_id` mediumint(8) unsigned NOT NULL,
  `city_id` smallint(5) unsigned NOT NULL,
  `subject_id` smallint(5) unsigned NOT NULL,
  `date_from` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `date_to` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `status` tinyint(4) NOT NULL DEFAULT '0',
  `order_of_arrival` tinyint(1) unsigned NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `by_hour_idx` (`teacher_id`,`order_of_arrival`,`status`,`city_id`,`subject_id`,`date_from`),
  KEY `order_arrival_idx` (`order_of_arrival`,`status`,`city_id`,`subject_id`,`date_from`,`date_to`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

অনুসন্ধান অনুসন্ধান

আমাকে এগুলি দ্বারা ফিল্টার করতে হবে: আসল তারিখের সময়, সিটি_আইডি, সাবজেক্ট_আইডি এবং যদি একটি স্লট উপলব্ধ থাকে (স্থিতি = 0)।

জন্য ঘনঘন ভিত্তিক আমি প্রতি শিক্ষকের জন্য প্রথম নিকটতম প্রাপ্তিসাধ্য প্রতিদিন সমস্ত উপলব্ধ স্লট দেখাতে হবে (ক নির্দিষ্ট দিনে সব সময় স্লট দেন এবং একই শিক্ষক চেয়ে আরো একদিন দেখাতে পারছি না)। ( ম্যাটেডগোডের সাহায্যে আমি কোয়েরিটি পেয়েছি )।

জন্য ভিত্তি পরিসীমা (order_of_arrival = 1), আমি নিকটস্থ পরিসীমা উপলব্ধ, শিক্ষক প্রতি শুধু একটা সময় প্রদর্শন করতে হবে।

প্রথম ক্যোয়ারী পৃথকভাবে 0.10 এমএস, দ্বিতীয় কোয়েরি 0.08 এমএস এবং ইউনিয়ন সব মিলিয়ে 300ms গড়ে চলে runs

(
    SELECT id, teacher_slots.teacher_id, date_from, date_to, order_of_arrival
    FROM teacher_slots
    JOIN (
        SELECT DATE(MIN(date_from)) as closestDay, teacher_id
        FROM teacher_slots
        WHERE   date_from >= '2014-04-10 08:00:00' AND order_of_arrival = 0
                AND status = 0 AND city_id = 6015 AND subject_id = 1
        GROUP BY teacher_id
    ) a ON a.teacher_id = teacher_slots.teacher_id
    AND DATE(teacher_slots.date_from) = closestDay
    WHERE teacher_slots.date_from >= '2014-04-10 08:00:00'
        AND teacher_slots.order_of_arrival = 0
        AND teacher_slots.status = 0
        AND teacher_slots.city_id = 6015
        AND teacher_slots.subject_id = 1
)

UNION ALL

(
    SELECT id, teacher_id, date_from, date_to, order_of_arrival
    FROM teacher_slots
    WHERE order_of_arrival = 1 AND status = 0 AND city_id = 6015 AND subject_id = 1
        AND (
            (date_from <= '2014-04-10 08:00:00' AND  date_to >= '2014-04-10 08:00:00')
            OR (date_from >= '2014-04-10 08:00:00')
        )
    GROUP BY teacher_id
)

ORDER BY date_from ASC;

প্রশ্ন

ইউনিয়নটিকে অনুকূলিত করার কোনও উপায় আছে, তাই আমি কেবলমাত্র একটি ক্যোয়ারির ভিত্তিতে সর্বাধিক 20 ডলার বা এমনকি বেড়ান ঘড়ির ভিত্তিতে (একটি আইএফ ইত্যাদির সাথে) এর যুক্তিসঙ্গত প্রতিক্রিয়া পেতে পারি?

এসকিউএল ফিডল: http://www.sqlfiddle.com/#!2/59420/1/0

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

আমি কেবলমাত্র তারিখটি সংরক্ষণ করেছি এমন একটি ক্ষেত্র "কেবল_ তারিখ_ফর্ম" তৈরি করে কিছু অস্বীকৃতির চেষ্টা করেছি যাতে আমি এটি পরিবর্তন করতে পারি ...

DATE(MIN(date_from)) as closestDay / DATE(teacher_slots.date_from) = closestDay

... এই

MIN(only_date_from) as closestDay / teacher_slots.only_date_from = closestDay

এটি ইতিমধ্যে আমার 100 মিমি সংরক্ষণ করেছে! এখনও গড়ে 200 মি।

উত্তর:


1

প্রথমত, আমি মনে করি আপনার মূল ক্যোয়ারী "সঠিক" নাও হতে পারে; আপনার SQLFiddle রেফারেন্স সঙ্গে, এটা আমার কাছে মনে হচ্ছে যেন আপনার সাথে সারি ফিরে দিতে হবে ID= 2, 3এবং 4(সঙ্গে সারি ছাড়াও ID= 1আপনি হয় আপনার বিদ্যমান যুক্তিবিজ্ঞান মনে হচ্ছে যেন আপনি এই অর্ধেক থেকে পেয়ে) অভিপ্রেত এই অন্যান্য সারির অন্তর্ভুক্ত করা হবে, কারণ তারা স্পষ্টভাবে OR (date_from >= '2014-04-10 08:00:00')আপনার দ্বিতীয় WHEREধারাটির অংশটি পূরণ করে ।

GROUP BY teacher_idআপনার আপনার দ্বিতীয় অংশে দফা UNIONআপনি ঐ সারি হারান ঘটাচ্ছে। এর কারণ আপনি প্রকৃতপক্ষে আপনার নির্বাচিত তালিকার কোনও কলামগুলিকে একত্রিত করছেন না, এবং এই ক্ষেত্রে GROUP BYআচরণটি 'সংজ্ঞা নির্ধারণ করা' অসুবিধে করবে।

এছাড়াও, আমি যখন আপনার দুর্বল পারফরম্যান্সটি ব্যাখ্যা করতে পারি না, তখন UNIONআপনার জিজ্ঞাসা থেকে একেবারে সরিয়ে আমি এটির জন্য কাজ করতে পারি:

একই টেবিল থেকে সারি পেতে দুটি পৃথক (এবং অংশে পুনরাবৃত্তি করা) যুক্তি ব্যবহারের পরিবর্তে, আমি আপনার যুক্তিটিকে যুক্তিযুক্ত ORএডের পার্থক্যগুলির সাথে একটি ক্যোয়ারিতে একীভূত করেছি - যেমন যদি কোনও সারি একটি বা অন্যটির সাথে মিলিত হয় আপনার মূল WHEREধারাগুলির মধ্যে এটি অন্তর্ভুক্ত রয়েছে। কারণ আমি প্রতিস্থাপিত করে থাকেন এটি সম্ভব (INNER) JOINআপনি এটি ব্যবহার করছেন সেটি closestDateএকটি সঙ্গে LEFT JOIN

এর LEFT JOINঅর্থ আমরা এখন আলাদা করতে সক্ষম হয়েছি যে কোন যুক্তিতে কোন যুক্তিকে একটি সারিতে প্রয়োগ করা উচিত; যদি যোগদানের কাজটি হয় (নিকটতম তারিখটি শূন্য নয়) আমরা প্রথম যুক্তি থেকে আপনার যুক্তি প্রয়োগ করি, তবে যোগদানটি যদি ব্যর্থ হয় (নিকটতম তারিখটি নাল হয়) তবে আমরা আপনার দ্বিতীয়ার্ধ থেকে যুক্তিটি প্রয়োগ করি।

সুতরাং এটি আপনার জিজ্ঞাসাটি ফিরিয়ে দেওয়া সমস্ত সারি (ফিডলটিতে) ফিরিয়ে দেবে এবং এটি অতিরিক্ত অতিরিক্তগুলিও তুলেছে।

  SELECT
    *

  FROM 
    teacher_slots ts

    LEFT JOIN 
    (
      SELECT 
        teacher_id,
        DATE(MIN(date_from)) as closestDay

      FROM 
        teacher_slots

      WHERE   
        date_from >= '2014-04-10 08:00:00' 
        AND order_of_arrival = 0
        AND status = 0 
        AND city_id = 6015 
        AND subject_id = 1

      GROUP BY 
        teacher_id

    ) a
    ON a.teacher_id = ts.teacher_id
    AND a.closestDay = DATE(ts.date_from)

  WHERE 
    /* conditions that were common to both halves of the union */
    ts.status = 0
    AND ts.city_id = 6015
    AND ts.subject_id = 1

    AND
    (
      (
        /* conditions that were from above the union 
           (ie when we joined to get closest future date) */
        a.teacher_id IS NOT NULL
        AND ts.date_from >= '2014-04-10 08:00:00'
        AND ts.order_of_arrival = 0
      ) 
      OR
      (
        /* conditions that were below the union 
          (ie when we didn't join) */
        a.teacher_id IS NULL       
        AND ts.order_of_arrival = 1 
        AND 
        (
          (
            date_from <= '2014-04-10 08:00:00' 
            AND  
            date_to >= '2014-04-10 08:00:00'
          )

          /* rows that met this condition were being discarded 
             as a result of 'difficult to define' GROUP BY behaviour. */
          OR date_from >= '2014-04-10 08:00:00' 
        )
      )
    )

  ORDER BY 
   ts.date_from ASC;

উপরন্তু, আপনি আপনার ক্যোয়ারী "আপ পরিপাটি" করতে পারেন আরো যাতে আপনি আপনার "এ প্লাগ" প্রয়োজন হবে না status, city_idএবং subject_idপরামিতি একাধিকবার।

এটি করার জন্য, aসেই কলামগুলি নির্বাচন করতে এবং সেই কলামগুলিতেও গোষ্ঠী তৈরি করতে সাবকিউরিটি পরিবর্তন করুন । তারপরে, JOINএর ONধারাটিতে তাদের ts.xxxসমতুল্য এই কলামগুলি ম্যাপ করা দরকার ।

আমি মনে করি না এটি নেতিবাচকভাবে পারফরম্যান্সকে প্রভাবিত করবে, তবে বড় ডেটাসেটে পরীক্ষা না করে নিশ্চিত হওয়া যায়নি।

সুতরাং আপনার যোগদানটি আরও দেখতে পাবেন:

LEFT JOIN 
(
  SELECT 
    teacher_id,
    status,
    city_id,
    subject_id,
    DATE(MIN(date_from)) as closestDay

  FROM 
    teacher_slots

  WHERE   
    date_from >= '2014-04-10 08:00:00' 
    AND order_of_arrival = 0
  /* These no longer required here...
    AND status = 0 
    AND city_id = 6015 
    AND subject_id = 1
  */

  GROUP BY 
    teacher_id,
    status,
    city_id,
    subject_id

) a
ON a.teacher_id = ts.teacher_id
AND a.status = ts.status 
AND a.city_id = ts.city_id 
AND a.subject_id = ts.city_id
AND a.closestDay = DATE(ts.date_from)

2

এই কোয়েরিটি চেষ্টা করে দেখুন:

(
select * from (SELECT id, teacher_slots.teacher_id, date_from, date_to,  order_of_arrival
FROM teacher_slots  WHERE teacher_slots.date_from >= '2014-04-10 08:00:00'
    AND teacher_slots.order_of_arrival = 0
    AND teacher_slots.status = 0
    AND teacher_slots.city_id = 6015
    AND teacher_slots.subject_id = 1) 
 teacher_slots
JOIN (
    SELECT DATE(MIN(date_from)) as closestDay, teacher_id
    FROM teacher_slots
    WHERE   date_from >= '2014-04-10 08:00:00' AND order_of_arrival = 0
            AND status = 0 AND city_id = 6015 AND subject_id = 1
    GROUP BY teacher_id
) a ON a.teacher_id = teacher_slots.teacher_id
AND DATE(teacher_slots.date_from) = closestDay

)

UNION ALL

(
SELECT id, teacher_id, date_from, date_to, order_of_arrival
FROM teacher_slots
WHERE order_of_arrival = 1 AND status = 0 AND city_id = 6015 AND subject_id = 1
    AND (
        (date_from <= '2014-04-10 08:00:00' AND  date_to >= '2014-04-10 08:00:00')
        OR (date_from >= '2014-04-10 08:00:00')
    )
GROUP BY teacher_id
)

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