ذاكرة التخزين المؤقت/إعادة استخدام استعلام فرعي في MySQL

StackOverflow https://stackoverflow.com/questions/658937

  •  20-08-2019
  •  | 
  •  

سؤال

لدي استعلام MySQL معقد للغاية يتضمن استخدام نفس الاستعلام الفرعي ثلاث مرات.هل سيقوم MySQL بالفعل بتشغيل الاستعلام الفرعي ثلاث مرات؟(إنها مكلفة.) إذا كان الأمر كذلك، فهل هناك طريقة يمكنني من خلالها إخبار MySQL بحفظ النتائج أو تخزينها مؤقتًا حتى لا يفعل ذلك؟يمكنني حفظ البيانات في مصفوفة كبيرة ثم إعادة إدخالها إلى MySQL، لكنني أفضل عدم نقلها وإعادتها إلى قاعدة البيانات بهذه الطريقة.

هذا هو الاستعلام الفرعي الذي يظهر ثلاث مرات:

SELECT id FROM programs 
WHERE submitter_id=32 AND id in (
    SELECT id FROM programs 
    WHERE feed_id=2478 AND id in (
        SELECT program_id FROM playlist_program_map 
        WHERE playlist_id=181)))

وإليك مثال للاستعلام الكامل الذي يظهر فيه الاستعلام:

SELECT object_id, programs.created AS created, 
MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE) AS relevance 
FROM comments_programs USE INDEX (text) 
LEFT JOIN programs ON programs.id=object_id 
WHERE object_id IN (
    SELECT id FROM programs 
    WHERE 1 AND id IN (
        SELECT id FROM programs 
        WHERE submitter_id=32 AND id in (
            SELECT id FROM programs 
            WHERE feed_id=2478 AND id in (
                SELECT program_id FROM playlist_program_map 
                WHERE playlist_id=181)))) 
AND MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE)>0)

UNION (

SELECT object_id, programs.created AS created, 
MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE) AS relevance 
FROM descriptions_programs USE INDEX (text) 
LEFT JOIN programs ON programs.id=object_id 
WHERE object_id IN (
    SELECT id FROM programs 
    WHERE 1 AND id IN (
        SELECT id FROM programs 
        WHERE submitter_id=32 AND id in (
            SELECT id FROM programs 
            WHERE feed_id=2478 AND id in (
                SELECT program_id FROM playlist_program_map 
                WHERE playlist_id=181)))) 
AND MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE)>0 AND current=1 ) 

UNION (

SELECT object_id, programs.created AS created, 
MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE) AS relevance 
FROM titles_programs USE INDEX (text) 
LEFT JOIN programs ON programs.id=object_id 
WHERE object_id IN (
    SELECT id FROM programs 
    WHERE 1 AND id IN (
        SELECT id FROM programs 
        WHERE submitter_id=32 AND id in (
            SELECT id FROM programs 
            WHERE feed_id=2478 AND id in (
                SELECT program_id FROM playlist_program_map 
                WHERE playlist_id=181)))) 
AND MATCH(text) AGAINST ('excellent ' IN BOOLEAN MODE)>0 AND current=1;
هل كانت مفيدة؟

المحلول

انظر ماذا EXPLAIN EXTENDED يقول.

إذا قال DEPENDENT SUBQUERY أو UNCACHEABLE SUBQUERY, ، ثم سيتم إعادة تقييمه في كل مرة يتم استخدامه.

يحدث هذا إذا كان الاستعلام الفرعي يستخدم متغيرات الجلسة أو كان استعلامًا فرعيًا مرتبطًا.

إذا لم يحدث ذلك، فمن المرجح أن يتم تخزينه مؤقتًا.

إذا لم يتم تخزين الاستعلام الفرعي في حالتك مؤقتًا، فسيتم إعادة تقييمه في كل حالة UNIONمجموعة إد.

ومع ذلك، يبدو أن الاستعلام الفرعي معقد للغاية.لماذا لا تستخدم فقط:

SELECT id
FROM   playlist_program_map ppm, programs p
WHERE  ppm.playlist_id = 181
       AND p.id = ppm.program_id
       AND submitter_id = 32
       AND feed_id = 2478

إذا كان لديك فهرس على playlist_program_map (playlist_id), ، يجب أن يعمل هذا الاستعلام مثل السحر.

هل يمكن أن تخبرني بأمرين آخرين:

  1. كم عدد الصفوف هناك playlist_program_map وكم DISTINCT playlist_id القيم هناك؟
    • كم عدد الصفوف هناك programs وكم DISTINCT submitter_id, feed_id أزواج هناك؟

من تعليقك أستطيع أن أستنتج أن هناك 10 programs لكل playlist في المتوسط، و 200 programs لكل (submitter, feed) زوج.وهذا يعني أن الفهرس الخاص بك قيد التشغيل playlist_program_map هو أكثر انتقائية من واحد على (submitter, feed), ، و playlist_program_map يجب أن تكون رائدة في الانضمام.

لا يبدو أن فهرس النص الكامل في حالتك انتقائي للغاية، نظرًا لأنك تحتاج إلى الانضمام 10 البرامج من 2,000,000.

من الأفضل أن تجرب ما يلي:

SELECT object_id, programs.created AS created
FROM   playlist_program_map ppm, programs p, comments_programs cp
WHERE  ppm.playlist_id = 181
       AND p.id = ppm.program_id
       AND p.submitter_id = 32
       AND p.feed_id = 2478
       AND cp.object_id = p.id
       AND cp.text REGEXP 'excellent'

, ، وكرر هذا لجميع الجداول الثلاثة.

نصائح أخرى

لسبب ما، الخلية في بنود مع تشغيل شبه حدد بطيئة جدا. من الأفضل استخدام الانضمام. يصبح لديك الاستعلام الفرعي:

ومعرف SELECT من برامج P1 INNER JOIN برامج P2 ON P1.id = P2.id INNER JOIN playlist_program_map PMAP ON P2.id = PMAP.program_id WHERE P1.submitter_id = 32 AND P2.feed_id = 2478 وPMAP.playlist_id = 181

ووسوف تعمل بشكل أسرع من ذلك بكثير.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top