سؤال

النظر في الاستعلام التالي:

SELECT * FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1;

ال ختم عمود في المعاملات الجدول هو طابع زمني وهناك فهرس عليه. كيف يمكنني تغيير هذا الاستعلام حتى يتجنب عمليات مسح الجدول الكاملة؟ (أي استخدام ختم خارج يوم() وظيفة)

شكرًا!

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

المحلول

هكذا سأفعل ذلك:

أضف بعض الحقول الإضافية: سنة أو شهر أو يوم أو حتى ساعة ، دقيقة اعتمادًا على حركة المرور التي تتوقعها. ثم قم ببناء مشغل لملء الحقول الإضافية ، وربما طرح الفاصل الزمني لمدة 3 ساعات مقدمًا. وأخيرا بناء بعض الفهرس على الحقول الإضافية.

نصائح أخرى

إذا كان الهدف هو تجنب عمليات مسح الجدول الكاملة وكان لديك مفتاح أساسي (قل اسم PK) للمعاملات ، ففكر في إضافة فهرس التغطية

ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)

ثم

SELECT * FROM Transactions WHERE PK IN (SELECT PK FROM Transactions
WHERE day(Stamp - interval 3 hour) = 1
 )

يجب ألا يستخدم هذا الاستعلام فحوصات الجدول الكاملة (ومع ذلك قد يقرر المحسن استخدام المسح الكامل ، إذا كان عدد الصفوف في الجدول صغيرًا أو لأي سبب إحصائي آخر :))

قد تكون طريقة أفضل هي استخدام جدول مؤقت بدلاً من الاسم الفرعي.

يمكنك في كثير من الأحيان إعادة كتابة الوظيفة حتى يكون لديك شيء يبدو WHERE Stamp=XXXX و xxxx هو بعض التعبير. يمكنك إنشاء سلسلة من العبارات لكل شهر ، WHERE Stamp BETWEEN timestamp('2010-01-01 00:00:00') AND timestamp ('2010-01-01 23:59:59') OR Stamp BETWEEN ..., ، لكنني لست متأكدًا من أن هذا سيستخدم الفهرس في هذه الحالة. كنت أقوم ببناء عمود كان يوم الشهر كما يوحي Petr.

احسب قيمة الطوابع المطلوبة بشكل منفصل قبل تشغيل استعلامك الرئيسي ، أي

الخطوة 1 - احسب قيمة الطوابع المطلوبة

الخطوة 2 - قم بتشغيل استعلام حيث ختم> (القيمة المحسوبة)

نظرًا لعدم وجود حساب في الخطوة 2 ، يجب أن تكون قادرًا على استخدام الفهرس الخاص بك.

إذا فهمت ذلك بشكل صحيح ، فأنت تريد أساسًا إعادة جميع الصفوف حيث يسقط الطابع في الأول في كل شهر (بعد طرح 3 ساعات)؟ إذا (وهذا كان كبيرًا إذا) ، فأنت تحتوي على نافذة ثابتة ، على سبيل المثال الـ 6 أشهر ، يمكنك فقط تعداد 6 اختبارات النطاق. لكن مع ذلك ، لست متأكدًا من أن الوصول المفهرس سيكون أسرع على أي حال.

select *
  from transactions
 where stamp between timestamp '2010-06-01 03:00:00' and timestamp '2010-06-02 02:59:59'
    or stamp between timestamp '2010-07-01 03:00:00' and timestamp '2010-07-02 02:59:59'
    or stamp between timestamp '2010-08-01 03:00:00' and timestamp '2010-08-02 02:59:59'
    or stamp between timestamp '2010-09-01 03:00:00' and timestamp '2010-09-02 02:59:59'
    or stamp between timestamp '2010-10-01 03:00:00' and timestamp '2010-10-02 02:59:59'
    or stamp between timestamp '2010-11-01 03:00:00' and timestamp '2010-11-02 02:59:59'
    or stamp between timestamp '2010-12-01 03:00:00' and timestamp '2010-12-02 02:59:59';

ناب لست متأكدًا من كيفية عمل الجزء المللي ثانية من الطابع الزمني. قد تحتاج إلى وضعه وفقًا لذلك.

إعادة صياغة إجابة بيتر قليلاً لتجنب البند في ، وجعلها من أجل Myisam أو InnoDB.

لميسام

ALTER TABLE Transactions ADD INDEX cover_1 (PK, Stamp)

أو ، لـ Innodb ، حيث يتم تضمين PK ضمنيًا في كل فهرس ،

ALTER TABLE Transactions ADD INDEX Stamp (Stamp)

ثم

SELECT * 
FROM Transactions LEFT JOIN
  (
  SELECT PK 
  FROM Transactions 
  WHERE DAYOFMONTH(Stamp - interval 3 hour) = 1
  ) a ON Transactions.PK=a.PK

لن يكون للاستماع الفرعي تنفيذ فهرس إلا ، وسيقوم الاستعلام الخارجي بسحب الصفوف فقط من الجدول حيث جاء A.PK.

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