ذاكرة التخزين المؤقت/إعادة استخدام استعلام فرعي في MySQL
سؤال
لدي استعلام 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)
, ، يجب أن يعمل هذا الاستعلام مثل السحر.
هل يمكن أن تخبرني بأمرين آخرين:
- كم عدد الصفوف هناك
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
ووسوف تعمل بشكل أسرع من ذلك بكثير.