لغز استعلام MySQL - العثور على ما كان يمكن أن يكون آخر موعد

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

سؤال

لقد نظرت في كل مكان ولم أجد طريقة ذكية للتعامل مع هذا ، على الرغم من أنني متأكد من أنه ممكن:

يحتوي جدول البيانات التاريخية على معلومات ربع سنوية:

CREATE TABLE Quarterly (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
PRIMARY KEY (unique_ID));

يحتوي جدول آخر من البيانات التاريخية (وهو كبير جدًا) على معلومات يومية:

CREATE TABLE Daily (
unique_ID INT UNSIGNED NOT NULL,
date_posted DATE NOT NULL,
datasource TINYINT UNSIGNED NOT NULL,
data FLOAT NOT NULL,
qtr_ID INT UNSIGNED,
PRIMARY KEY (unique_ID));

إن حقل QTR_ID ليس جزءًا من تغذية البيانات اليومية التي ملأت قاعدة البيانات - بدلاً من ذلك ، أحتاج إلى ملء حقل QTR_ID بأثر رجعي في الجدول اليومي مع معرف الصف الفصلي. أن daily.date_posted لمصدر البيانات هذا.

على سبيل المثال ، إذا كانت البيانات الفصلية

101 2009-03-31 1 4.5
102 2009-06-30 1 4.4
103 2009-03-31 2 7.6
104 2009-06-30 2 7.7
105 2009-09-30 1 4.7

والبيانات اليومية هي

1001 2009-07-14 1 3.5 ??
1002 2009-07-15 1 3.4 &&
1003 2009-07-14 2 2.3 ^^

ثم نريد ؟؟ يتم تعيين حقل QTR_ID "102" كأحدث ربع لمصدر البيانات في ذلك التاريخ ، وسيكون && أيضًا "102" ، وسيكون ^ ^ "104".

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

لقد جربت مجموعة متنوعة من الوصلات ، باستخدام Datediff (حيث يتمثل التحدي في إيجاد الحد الأدنى لقيمة Datediff أكبر من الصفر) ، ومحاولات أخرى ولكن لا شيء يعمل بالنسبة لي - عادةً ما ينهار بناء الجملة في مكان ما. أي أفكار مرحب بها - سأقوم بتنفيذ أي أفكار أو مفاهيم أساسية وأبلغ تقريرها.

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

المحلول

فقط الاسم الفرعي لمعرف الربع باستخدام شيء مثل:

(
 SELECT unique_ID 
 FROM Quarterly 
 WHERE 
     datasource = ? 
     AND date_posted >= ? 
 ORDER BY
     unique_ID ASC
 LIMIT 1
)

بالطبع ، ربما لن يمنحك هذا أفضل أداء ، ويفترض أن التواريخ تضاف إلى فصلية متتالية (خلاف ذلك order by date_posted). ومع ذلك ، يجب أن يحل مشكلتك.

يمكنك استخدام هذا الاسم الفرعي الخاص بك INSERT أو UPDATE البيانات كقيمة لك qtr_ID حقل لك Daily الطاولة.

نصائح أخرى

يبدو أن ما يلي يعمل على النحو المقصود تمامًا ولكنه بالتأكيد قبيح (مع ثلاث مكالمات لنفس المؤرخ !!) ، ربما من خلال رؤية استعلام عاملة قد يتمكن شخص ما من تقليله أو تحسينه:

UPDATE Daily SET qtr_ID = (select unique_ID from Quarterly
WHERE Quarterly.datasource = Daily.datasource AND
DATEDIFF(Daily.date_posted, Quarterly.date_posted) = 
(SELECT MIN(DATEDIFF(Daily.date_posted, Quarterly.date_posted)) from Quarterly
WHERE Quarterly.datasource = Daily.datasource AND
DATEDIFF(Daily.date_posted, Quarterly.date_posted) > 0));

بعد مزيد من العمل في هذا الاستعلام ، انتهى بي الأمر بتحسينات هائلة في الأداء على المفهوم الأصلي. كان التحسن الأكثر أهمية هو إنشاء مؤشرات في كل من الجداول اليومية والفصلية - في اليومية قمت بإنشاء مؤشرات على (DataSource و Date_posted) و (Date_posted ، DataSource) باستخدام Btree وعلى (DataSource) باستخدام التجزئة ، وفي ربع سنوي فعلت نفس الشيء شيء. هذا مبالغة ، لكنه تأكد من أن لدي خيار يمكن أن يستخدمه محرك الاستعلام. هذا قلل من وقت الاستعلام إلى أقل من 1 ٪ مما كان عليه. (!!)

بعد ذلك ، علمت أنه بالنظر إلى ظروف بلدي الخاصة ، يمكنني استخدام Max () بدلاً من الطلب والحد حتى أستخدم مكالمة إلى Max () للحصول على الفريد المناسبين. هذا قلل من وقت الاستعلام بحوالي 20 ٪.

أخيرًا ، تعلمت أنه من خلال محرك تخزين Innodb ، يمكنني تقسيم جزء الجدول اليومي الذي كنت أقوم بتحديثه مع أي استفسار واحد ، مما سمح لي بتعدد الاستعلامات مع القليل من الحشوة والبرمجة النصية. عملت المعالجة الموازية بشكل جيد وقلل كل مؤشر ترابط وقت الاستعلام خطيًا.

لذا ، فإن الاستعلام الأساسي الذي يؤدي حرفيًا أفضل 1000 مرة من محاولتي الأولى هو:

UPDATE Daily
SET qtr_ID =
(
  SELECT MAX(unique_ID)
  FROM Quarterly
  WHERE Daily.datasource = Quarterly.datasource AND
        Daily.date_posted > Quarterly.dateposted
)
WHERE unique_ID > ScriptVarLowerBound AND
      unique_ID <= ScriptVarHigherBound
;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top