هل هناك طريقة جيدة للتحقق من القواعد مقابل الأعمدة n؟

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

  •  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 البحث في الفهرس عن التطابقات، ثم البحث مرة أخرى عن القيم الخالية.لذلك نستخدم الفهرس مرتين، ولكن لا نستخدم الفهرس بالكامل أبدًا.

ولكن مع الدمج، يكون لديك عبء تنفيذ وظيفة الدمج على كل قيمة عمود.ربما يعتمد أيهما أسرع على عدد القواعد التي لديك، وعدد الأعمدة في كل صف، والفهرس المستخدم، إن وجد.

ما إذا كان أكثر قابلية للقراءة هي مسألة رأي.

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