سؤال

حسنا، إليك استعلام أقوم بتشغيله الآن على طاولة يحتوي على 45000 سجل ويقوم بحجم 65 ميجابايت ... وعلى وشك الحصول على أكبر وأكبر (لذلك يجب أن أفكر في الأداء في المستقبل أيضا هنا):

SELECT count(payment_id) as signup_count, sum(amount) as signup_amount
FROM payments p
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND tm_completed IS NOT NULL
AND member_id NOT IN (SELECT p2.member_id FROM payments p2 WHERE p2.completed=1 AND p2.tm_completed < '2009-05-01' AND p2.tm_completed IS NOT NULL GROUP BY p2.member_id)

وكما قد تتخيل أو لا تتخيل - إنه يخنق خادم MySQL إلى مسدود ...

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

الآن، هل هناك أي طريقة ممكنة لتحسين هذا الاستعلام لاستخدام موارد أقل أو أي شيء، والتوقف عن أخذ موارد MySQL الخاصة بي إلى ركبتيهم ...؟

هل أفتقد أي معلومات لتوضيح هذا أكثر؟ اسمحوا لي أن أعرف...

تعديل:

فيما يلي الفهارس الموجودة بالفعل على هذا الجدول:

الابتدائي الأساسي 46757 payment_id

Affember_id Index 23378 الأعضاء_id

فهرس Payer_id 11689 Payer_id

فهرس الكوبون 1 كوبون

مؤشر TM_EDDED 46757 TM_EDDED، Product_id

مؤشر TM_COMPLETED 46757 TM_COMPLETED، product_id

هل كانت مفيدة؟

المحلول

تلك الأنواع من IN السطخت بطيئة بعض الشيء في MySQL. أود إعادة صياغة ذلك مثل هذا:

SELECT COUNT(1) AS signup_count, SUM(amount) AS signup_amount
FROM   payments p
WHERE  tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND    completed > 0
AND    NOT EXISTS (
           SELECT member_id
           FROM   payments
           WHERE  member_id = p.member_id
           AND    completed = 1
           AND    tm_completed < '2009-05-01');

التحقيق 'tm_completed IS NOT NULLليست ضرورية لأنها ضمنية من قبل BETWEEN شرط.

تأكد أيضا من وجود فهرس على:

(tm_completed, completed)

نصائح أخرى

كان لدي متعة وضع هذا الحل الذي لا يتطلب عملية استقامة

SELECT count(p1.payment_id) as signup_count, 
       sum(p1.amount)       as signup_amount  

  FROM payments p1
       LEFT JOIN payments p2 
       ON p1.member_id = p2.member_id
   AND p2.completed = 1
   AND p2.tm_completed < date '2009-05-01'

 WHERE p1.completed > 0
   AND p1.tm_completed between date '2009-05-01' and date '2009-05-30'
   AND p2.member_id IS NULL;

تجنب استخدامها مع إعالة فرعية؛ لا يحسن MySQL هذه جيدا (على الرغم من أن هناك تحسينات معلقة في 5.4 و 6.0 فيما يتعلق بهذا (انظر هنا). من المحتمل أن تحصل على إعادة كتابة هذا كضمان دفعة أداء:

SELECT count(payment_id) as signup_count, sum(amount) as signup_amount
FROM payments p
LEFT JOIN (SELECT p2.member_id
          FROM payments p2
          WHERE p2.completed=1
          AND p2.tm_completed < '2009-05-01'
          AND p2.tm_completed IS NOT NULL
          GROUP BY p2.member_id) foo
ON p.member_id = foo.member_id AND foo.member_id IS NULL
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND tm_completed IS NOT NULL

ثانيا، أود أن أرى مخطط الجدول الخاص بك؛ هل تستخدم الفهارس؟

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