هل هناك طريقة جيدة للتحقق من القواعد مقابل الأعمدة n؟
-
09-09-2019 - |
سؤال
لنفترض أن لديك قواعد جدول مكونة من 3 أعمدة A وB وC.عندما تدخل البيانات إلى النظام، أريد معرفة ما إذا كان أي صف في جدول RULES يطابق بياناتي بشرط أنه إذا كان العمود المقابل في جدول RULES خاليًا، فإن جميع البيانات متطابقة.لغة SQL الواضحة هي:
SELECT * FROM RULES
WHERE (A = :a OR A IS NULL)
AND (B = :b OR B IS NULL)
AND (C = :c OR C IS NULL)
لذلك إذا كان لدي قواعد:
RULE A B C 1 50 NULL NULL 2 51 xyz NULL 3 51 NULL 123 4 NULL xyz 456
سيطابق الإدخال (50، xyz، 456) القاعدتين 1 و4.
سؤال: هل هناك طريقة أفضل للقيام بذلك؟مع 3 حقول فقط، لا توجد مشكلة.لكن الجدول الفعلي سيحتوي على 15 عمودًا وأنا قلق بشأن مدى جودة مقياس SQL.
المضاربة: تتضمن عبارة SQL البديلة التي توصلت إليها إضافة عمود إضافي إلى الجدول مع عدد الحقول غير الفارغة.(لذلك في المثال، قيمة الأعمدة للقواعد 1-4 هي 1 و2 و2 و2 على التوالي.) باستخدام عمود "col_count" هذا، يمكن أن يكون التحديد:
SELECT * FROM RULES
WHERE (CASE WHEN A = :a THEN 1 ELSE 0 END)
+ (CASE WHEN B = :b THEN 1 ELSE 0 END)
+ (CASE WHEN C = :c THEN 1 ELSE 0 END)
= COL_COUNT
لسوء الحظ، ليس لدي ما يكفي من البيانات النموذجية لمعرفة أي من هذه الأساليب سيكون له أداء أفضل.قبل أن أبدأ في إنشاء قواعد عشوائية، اعتقدت أنني سأسأل هنا ما إذا كان هناك نهج أفضل.
ملحوظة: تقنيات استخراج البيانات وقيود الأعمدة غير ممكنة هنا.يجب التحقق من البيانات عند دخولها إلى النظام ومن ثم يمكن وضع علامة نجاح/فشل عليها على الفور.ويتحكم المستخدمون في إضافة القواعد أو إزالتها حتى لا أتمكن من تحويل القواعد إلى قيود الأعمدة أو بيانات تعريف البيانات الأخرى.
شيء أخير، في النهاية أحتاج إلى قائمة بجميع القواعد التي فشلت البيانات في اجتيازها.لا يمكن إحباط الحل عند الفشل الأول.
شكرًا.
المحلول
الاستعلام الأول الذي قدمته مثالي.أشك حقًا في أن إضافة العمود الذي كنت تتحدث عنه سيمنحك المزيد من السرعة، نظرًا لأنه يتم التحقق من الخاصية NOT NULL لكل إدخال على أي حال، نظرًا لأن كل مقارنة بـ NULL تؤدي إلى خطأ.لذلك أعتقد ذلك x=y
يتم توسيعه إلى x IS NOT NULL AND x=y
داخليا.ربما يمكن لشخص آخر توضيح ذلك.
جميع التحسينات الأخرى التي يمكنني التفكير فيها قد تتضمن الحساب المسبق أو التخزين المؤقت.يمكنك إنشاء جداول [مؤقتة] مطابقة لقواعد معينة أو إضافة أعمدة أخرى تحتوي على قواعد مطابقة.
نصائح أخرى
هل هناك عدد كبير جدًا من الصفوف/القواعد؟إذا لم يكن الأمر كذلك (هذا أمر شخصي، ولكن على سبيل المثال أقل من 10000)، فيمكنك إنشاء فهارس لجميع الأعمدة.
سيؤدي ذلك إلى زيادة السرعة بشكل كبير ولن تشغل الفهارس مساحة كبيرة.
إذا كنت لا تخطط لإنشاء جدول ضخم من القواعد، فأنا أراهن أن أسلوبك جيد بشرط أن تقوم بفهرسة جميع الأعمدة.
لماذا لا تضع فهارس لجدول القواعد الخاص بك حسب القيم؟إذا تستطيع
SELECT myvalue FROM RULES_A
يبدو أن ما لديك حقًا هو القواعد ومجموعات القواعد.إن تصميمه بهذه الطريقة لن يجعل هذا الترميز أكثر بساطة فحسب، بل سيجعل النموذج أيضًا قابلاً للتوسيع عندما تقرر أنك بحاجة إلى 16 عمودًا.
على سبيل المثال:
CREATE TABLE Rules (
rule_id INT NOT NULL,
rule_category CHAR(1) NOT NULL, -- This is like your column idea
rule_int_value INT NULL,
rule_str_value VARCHAR(20) NULL,
CONSTRAINT PK_Rules PRIMARY KEY CLUSTERED (rule_id),
CONSTRAINT CK_Rules_one_value CHECK (rule_int_value IS NULL OR rule_str_value IS NULL)
)
CREATE TABLE Rule_Sets (
rule_set_id INT NOT NULL,
rule_id INT NOT NULL,
CONSTRAINT PK_Rule_Sets PRIMARY KEY CLUSTERED (rule_set_id, rule_id)
)
بعض البيانات التي قد تتطابق مع القواعد المحددة الخاصة بك:
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (1, 'A', 50, NULL)
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (2, 'A', 51, NULL)
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (3, 'B', NULL, 'xyz')
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (4, 'C', 123, NULL)
INSERT INTO Rules (rule_id, rule_category, rule_int_value, rule_str_value)
VALUES (5, 'C', 456, NULL)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (1, 1)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (2, 2)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (2, 3)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (3, 2)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (3, 4)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (4, 3)
INSERT INTO Rule_Sets (rule_set_id, rule_id) VALUES (4, 5)
نص اختباري يؤكد نفس الإجابة التي تتوقعها:
DECLARE
@a INT,
@b VARCHAR(20),
@c INT
SET @a = 50
SET @b = 'xyz'
SET @c = 456
SELECT DISTINCT
rule_set_id AS failed_rule_set_id
FROM
Rule_Sets RS
WHERE
NOT EXISTS (SELECT * FROM Rules R WHERE R.rule_id = RS.rule_id AND @a = R.rule_int_value) AND
NOT EXISTS (SELECT * FROM Rules R WHERE R.rule_id = RS.rule_id AND @b = R.rule_str_value) AND
NOT EXISTS (SELECT * FROM Rules R WHERE R.rule_id = RS.rule_id AND @c = R.rule_int_value)
إذا كان بإمكانك تقديم بيانات الإدخال في نموذج قائم على المجموعة بدلاً من كمعلمات فردية، فيمكن أن تكون عبارة SQL النهائية أكثر ديناميكية ولن تحتاج إلى النمو عند إضافة أعمدة إضافية.
SELECT * FROM RULES
WHERE (A = :a OR A IS NULL)
AND (B = :b OR B IS NULL)
AND (C = :c OR C IS NULL);
اعتمادًا على نظام RBDMS الخاص بك، قد يكون هذا أكثر كفاءة أو لا يكون، ولكن ليس كثيرًا:
SELECT * FROM RULES
WHERE coalesce(A, :a) = :a
AND coalesce(B, :b) = :b
AND coalesce(C, :c) = :c ;
في MySQL (قد يقوم نظام RBDMS الخاص بك بذلك بشكل مختلف)، يسمح هذا الاستعلام بـ index
مسح بدلاً من أ ref_or_null
المسح الضوئي، إذا كان هناك فهرس قابل للتطبيق.إذا كان الفهرس يغطي جميع الأعمدة، فإنه يسمح باستخدام الفهرس بأكمله (وفي الواقع، إذا كان الفهرس يغطي جميع الأعمدة، فإن الفهرس يكون الطاولة).
مع استفسارك، أ ref_or_null
يتم الوصول بدلاً من index
الوصول، ويتم استخدام العمود الأول فقط في فهرس متعدد الأعمدة.مع ref_or_null
, يجب على MySQL البحث في الفهرس عن التطابقات، ثم البحث مرة أخرى عن القيم الخالية.لذلك نستخدم الفهرس مرتين، ولكن لا نستخدم الفهرس بالكامل أبدًا.
ولكن مع الدمج، يكون لديك عبء تنفيذ وظيفة الدمج على كل قيمة عمود.ربما يعتمد أيهما أسرع على عدد القواعد التي لديك، وعدد الأعمدة في كل صف، والفهرس المستخدم، إن وجد.
ما إذا كان أكثر قابلية للقراءة هي مسألة رأي.