طريقة علائقية سريعة لتخزين بيانات الشجرة (على سبيل المثال التعليقات المترابطة على المقالات)

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

سؤال

لدي cms الذي يقوم بتخزين التعليقات ضد المقالات.يمكن أن تكون هذه التعليقات مترابطة وغير مترابطة.على الرغم من أنها متماثلة من الناحية الفنية فقط مع ترك عمود الرد فارغًا عندما لا يكون مترابطة.يعمل تطبيقي على sqlLite وMySQL وpgsql لذا أحتاج إلى لغة SQL قياسية إلى حد ما.

لدي حاليا جدول التعليقات

comment_id
article_id
user_id
comment
timestamp
thread (this is the reply column)

سؤالي هو معرفة أفضل طريقة لتمثيل التعليقات المترابطة في قاعدة البيانات.ربما في جدول منفصل يدعم مجموعة الشجرة بدون محتوى وجدول بسيط للاحتفاظ بالنص؟ربما بالطريقة التي هي عليها بالفعل؟ربما طريقة أخرى؟

إذا كانت التعليقات غير متسلسلة، فيمكنني بسهولة أن أطلبها حسب الطابع الزمني.

إذا كانت مترابطة فأنا أفرز مثل هذا

ORDER BY SUBSTRING(c.thread, 1, (LENGTH(c.thread) - 1))

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

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

المحلول

أنا حقا أحب كيف دروبال يحل هذه المشكلة.يقوم بتعيين معرف موضوع لكل تعليق.يبدأ هذا المعرف عند 1 للتعليق الأول.إذا تمت إضافة رد على هذا التعليق، فإن المعرف 1.1 تم تعيينه لذلك.رد على التعليق 1.1 يتم إعطاء معرف الموضوع 1.1.1.أخي التعليق 1.1 يتم إعطاء معرف الموضوع 1.2.انت وجدت الفكرة.يمكن إجراء حساب معرفات سلاسل المحادثات هذه بسهولة باستخدام استعلام واحد عند إضافة تعليق.

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

1
1.1
1.1.1
1.2
1.2.1

هناك بعض القضايا التي يجب حلها:

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

يحل دروبال المشكلة الأولى بطريقة أكثر تعقيدًا باستخدام نظام ترقيم يسمى vancode.أما المشكلة الثانية، فقد تم حلها عن طريق إضافة شرطة مائلة عكسية (رمز ASCII الخاص بها أعلى من الأرقام) إلى معرفات الخيوط عند الفرز بترتيب تنازلي.يمكنك العثور على مزيد من التفاصيل حول هذا التنفيذ عن طريق التحقق من الكود المصدري لـ وحدة التعليقات (راجع التعليق الكبير قبل الوظيفة comment_get_thread).

نصائح أخرى

أعلم أن الإجابة متأخرة بعض الشيء، ولكن بالنسبة لبيانات الشجرة، استخدم جدول الإغلاقhttp://www.slideshare.net/billkarwin/models-for-hierarchical-data

ويصف 4 طرق:

  • قائمة المجاورة (المفتاح الخارجي الأصلي البسيط)
  • تعداد المسار (استراتيجية دروبال المذكورة في الإجابة المقبولة)
  • مجموعات متداخلة
  • جدول الإغلاق (تخزين حقائق السلف/السليل في علاقة منفصلة [جدول]، مع عمود مسافة محتمل)

يتمتع الخيار الأخير بمزايا عمليات CRUD السهلة مقارنة بالباقي.التكلفة هي المساحة، وهي بحجم O(n^2) في عقد شجرة الأرقام في أسوأ الحالات، ولكنها ربما ليست سيئة للغاية في الممارسة العملية.

ولسوء الحظ، فإن أساليب SQL الخالصة للقيام بذلك بطيئة جدًا.

ال NESTED SETS مقترح من قبل @Marc W إنها أنيقة للغاية ولكنها قد تتطلب تحديث الشجرة بأكملها إذا وصلت فروع شجرتك إلى النطاقات، الأمر الذي قد يكون بطيئًا للغاية.

راجع هذه المقالة في مدونتي حول كيفية القيام بذلك بسرعة MySQL:

ستحتاج إلى إنشاء وظيفة:

CREATE FUNCTION hierarchy_connect_by_parent_eq_prior_id(value INT) RETURNS INT
NOT DETERMINISTIC
READS SQL DATA
BEGIN
        DECLARE _id INT;
        DECLARE _parent INT;
        DECLARE _next INT;
        DECLARE CONTINUE HANDLER FOR NOT FOUND SET @id = NULL;

        SET _parent = @id;
        SET _id = -1;

        IF @id IS NULL THEN
                RETURN NULL;
        END IF;

        LOOP
                SELECT  MIN(id)
                INTO    @id
                FROM    t_hierarchy
                WHERE   parent = _parent
                        AND id > _id;
                IF @id IS NOT NULL OR _parent = @start_with THEN
                        SET @level = @level + 1;
                        RETURN @id;
                END IF;
                SET @level := @level - 1;
                SELECT  id, parent
                INTO    _id, _parent
                FROM    t_hierarchy
                WHERE   id = _parent;
        END LOOP;
END

واستخدامها في استعلام مثل هذا:

SELECT  hi.*
FROM    (
        SELECT  hierarchy_connect_by_parent_eq_prior_id(id) AS id, @level AS level
        FROM    (
                SELECT  @start_with := 0,
                        @id := @start_with,
                        @level := 0
                ) vars, t_hierarchy
        WHERE   @id IS NOT NULL
        ) ho
JOIN    t_hierarchy hi
ON      hi.id = ho.id

هذا بالطبع MySQL محدد ولكنه سريع جدًا.

إذا كنت تريد أن يكون هذا محمولًا بين PostgreSQL و MySQL, ، يمكنك استخدام PostgreSQLمساهمة ل CONNECT BY وقم بلف الاستعلام في إجراء مخزن بنفس الاسم لكلا النظامين.

وأنا فعلت هذا بنفسي، في الواقع! لقد استخدمت نموذج مجموعة متداخلة من تمثيل البيانات الهرمية في قاعدة بيانات علائقية.

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

وكنت قد حصلت على الاختيار بين الجوار ونماذج مجموعة متداخلة. المادة إدارة البيانات الهرمية في الخلية يجعل لمقدمة لطيفة.

لمناقشة النظرية، انظر Celko في الأشجار والتدرجات .

من السهل بدلا لتنفيذ قائمة مترابطة إذا كانت قاعدة البيانات تدعم وظائف النوافذ. كل ما تحتاجه هو إشارة متكررة في جدول قاعدة البيانات التي تستهدفها، مثل:

create Tablename (
  RecordID integer not null default 0 auto_increment,
  ParentID integer default null references RecordID,
  ...
)

ويمكنك بعد ذلك استخدام العودية التعبير الجدول المشترك لعرض عرض مترابطة. مثال على ذلك هو هنا .

في الواقع، فإنه يجب أن يكون هناك توازن بين القراءة والكتابة.

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

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

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

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