MySQL على التحديث الرئيسي المكرر مع عمود لا يغلى في مفتاح فريد

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

  •  18-09-2019
  •  | 
  •  

سؤال

تحتوي قاعدة بيانات Analytics Web MySQL على جدول ملخص يتم تحديثه طوال اليوم حيث يتم استيراد نشاط جديد. نحن نستخدم على التحديث الرئيسي المكرر من أجل أن تكتسب التلخيص العمليات الحسابية السابقة، ولكن تواجه صعوبة لأن أحد الأعمدة في المفتاح الفريد للطاولة الموجز هو FK اختياري، وتحتوي على قيم فارغة.

تهدف هذه الخامة إلى أن تعني "عدم الحاضر، وجميع هذه الحالات مكافئة". بالطبع، يعامل MySQL عادة ما معنى "غير معروف، وجميع هذه الحالات ليست مكافئة".

الهيكل الأساسي هو كما يلي:

جدول "نشاط" يحتوي على إدخال لكل جلسة، كل ينتمي إلى حملة، مع مرشح اختياري ومعرفات المعاملات للحصول على بعض الإدخالات.

CREATE TABLE `Activity` (
    `session_id` INTEGER AUTO_INCREMENT
    , `campaign_id` INTEGER NOT NULL
    , `filter_id` INTEGER DEFAULT NULL
    , `transaction_id` INTEGER DEFAULT NULL
    , PRIMARY KEY (`session_id`)
);

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

CREATE TABLE `Summary` (
    `day` DATE NOT NULL
    , `campaign_id` INTEGER NOT NULL
    , `filter_id` INTEGER DEFAULT NULL
    , `sessions` INTEGER UNSIGNED DEFAULT NULL
    , `transactions` INTEGER UNSIGNED DEFAULT NULL
    , UNIQUE KEY (`day`, `campaign_id`, `filter_id`)
) ENGINE=MyISAM;

يعد استعلام التلخيص الفعلي مثل ما يلي، عد عدد الجلسات والمعاملات، ثم تجميعها من خلال الحملة و (اختياري) مرشح.

INSERT INTO `Summary` 
    (`day`, `campaign_id`, `filter_id`, `sessions`, `transactions`)
    SELECT `day`, `campaign_id`, `filter_id
        , COUNT(`session_id`) AS `sessions`
        , COUNT(`transaction_id` IS NOT NULL) AS `transactions`
    FROM Activity
    GROUP BY `day`, `campaign_id`, `filter_id`
ON DUPLICATE KEY UPDATE
    `sessions` = VALUES(`sessions`)
    , `transactions` = VALUES(`transactions`)
;

كل شيء يعمل بشكل رائع، باستثناء ملخص الحالات التي يكون فيها filter_id فارغة. في هذه الحالات، لا يطابق جملة التحديث الرئيسية المكرر مع الصف الحالي، ويتم كتابة صف جديد في كل مرة. هذا يرجع إلى حقيقة أن "null! = null". ما نحتاجه، ومع ذلك، هو "null = null" عند مقارنة المفاتيح الفريدة.

أنا أبحث عن أفكار للمجاملات أو ردود الفعل على أولئك الذين وصلنا مع حتى الآن. الحلول التي فكرنا فيها حتى الآن.

  1. حذف جميع إدخالات الموجز التي تحتوي على قيمة مفاتيح فارغة قبل تشغيل التلخيص. (هذا ما نقوم به الآن) يحتوي هذا على التأثير الجانبي السلبي لنتائج العودة مع البيانات المفقودة إذا تم تنفيذ استعلام أثناء عملية التلخيص.

  2. تغيير العمود الفارغ الافتراضي إلى الافتراضي 0، والذي يسمح بمفتاح فريد من نوعه باستمرار. هذا له التأثير الجانبي السلبي لتعقد تطور الاستعلامات بشكل مفرط على جدول الملخص. يجبرنا على استخدام الكثير من "Case Filter_ID = 0 ثم Null Light_id Light"، ويجعل من أجل الانضمام المحرج لأن جميع الجداول الأخرى تحتوي على خيال فعلي ل Filter_ID.

  3. قم بإنشاء طريقة عرض إرجاع "Case Filter_ID = 0 ثم Null Light_ID End"، واستخدام طريقة العرض هذه بدلا من الجدول مباشرة. يحتوي جدول الملخص على بضع مئات من الألف من الصفوف، وقيل لي أداء العرض هو ضعيف جدا.

  4. اسمح بإنشاء الإدخالات المكررة، وحذف الإدخالات القديمة بعد إكمال التلخيص. لديه مشاكل مماثلة لحذفها في وقت مبكر.

  5. إضافة عمود بديل يحتوي على 0 ل NULL، واستخدام هذا بديل في المفتاح الفريد (في الواقع يمكننا استخدام المفتاح الأساسي إذا كانت جميع الأعمدة ليست فارغة).
    يبدو هذا الحل معقول، إلا أن المثال أعلاه هو مثال فقط؛ تحتوي قاعدة البيانات الفعلية على نصف دزينة من الجداول الملخص، واحدة منها تحتوي على أربعة أعمدة غير قابلة للغة في المفتاح الفريد. هناك قلق من بعض أن النفقات العامة أكثر من اللازم.

هل لديك معلومات أفضل أو هيكل جدول أو عملية تحديث أو أفضل ممارسة MySQL التي يمكن أن تساعد؟

تحرير: لتوضيح "معنى NULL"

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

السبب الوحيد لوضعها في مفتاح فريد من نوعه في الجدول الملخص هو السماح بالتحديث التلقائي (حسب التحديث الرئيسي المكرر) عند إعادة حساب التقارير الموجزة.

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

تغيير بقية جداول البيانات للحصول على "هناك

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

المحلول

أعتقد أن شيئا ما على غرار (2) هو حقا أفضل رهان - أو، على الأقل، سيكون إذا كنت بدأت من الصفر. في SQL، يعني null غير معروف. إذا كنت تريد بعض المعنى الآخر، فيمكنك حقا استخدام قيمة خاصة لذلك، و 0 بالتأكيد اختيار موافق.

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

يجب أن تتقدم أيضا وإنشاء إدخال "غير موجود" في الجدول المشار إليه أيضا، للحفاظ على تقييد FK صالح (وتجنب الحالات الخاصة).

PS: الجداول W / OA المفتاح الأساسي ليست الجداول العلائقية وينبغي تجنبها حقا.

تحرير 1.

هممم، في هذه الحالة، هل تحتاج فعلا إلى التحديث الرئيسي المكرر؟ إذا كنت تقوم بإدخال ... حدد، ثم ربما تفعل. ولكن إذا كان تطبيقك يوفر البيانات، فما عليك سوى القيام بذلك باليد - قم بالتحديث (رسم الخرائط zip = null ل zip is null)، تحقق من عدد الصفوف التي تم تغييرها (يعيد MySQL هذا)، إذا كان 0 يقوم بالإدراج.

نصائح أخرى

تغيير العمود الفارغ الافتراضي إلى الافتراضي 0، والذي يسمح بمفتاح فريد من نوعه باستمرار. هذا له التأثير الجانبي السلبي لتعقد تطور الاستعلامات بشكل مفرط على جدول الملخص. يجبرنا على استخدام الكثير من "Case Filter_ID = 0 ثم Null Light_id Light"، ويجعل من أجل الانضمام المحرج لأن جميع الجداول الأخرى تحتوي على خيال فعلي ل Filter_ID.

قم بإنشاء طريقة عرض إرجاع "Case Filter_ID = 0 ثم Null Light_ID End"، واستخدام طريقة العرض هذه بدلا من الجدول مباشرة. يحتوي جدول الملخص على بضع مئات من الألف من الصفوف، وقيل لي أداء العرض هو ضعيف جدا.

عرض الأداء في MySQL 5.x سيكون على ما يرام، حيث أن العرض لا يفعل شيئا سوى استبدال صفر مع فارغة. ما لم تستخدم المجاميع / الأنواع في طريقة عرض، سيتم إعادة كتابة معظم أي استفسار ضد العرض بواسطة Optimizer الاستعلام لضرب الجدول الأساسي فقط.

وبالطبع، نظرا لأنها FK، سيتعين عليك إنشاء إدخال في الجدول المشار إليه مع معرف صفر.

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

على سبيل المثال

إنشاء جدول إذا لم يكن موجودا (ID ID ID INT INTER الابتدائي AUTO_INCREMEMENT، DEATBIN تاريخ غير فارغ، BAZ1_ID Int Default Null، VBAZ1_ID INT AS (Coalesce (BAZ1_ID، -1)) المخزن، BAZ2_ID Int Default Null، VBAZ2_ID INT AS (Coalsce (BAZ2_ID، -1))) تخزينها، بلام مزدوج لا لاغية، فريدة من نوعها (DateBin، vbaz1_id، vbaz2_id))؛ إدراج في شريط (DateBin، Baz1_id، Baz2_id، Blam) القيم ('2016-06-01'، NULL، NULL، 777) على تحديث مفتاح مكررة Blam = القيم (Blam)؛

بالنسبة ل Mariadb، استبدل المخزنة بالمستمر، تتطلب الفهارس الثابتة.

أعمدة MySQL Mariadb الأعمدة الافتراضية

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