MySQL - أفضل طريقة للتعامل مع هذه البيانات الهرمية؟

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

  •  01-10-2019
  •  | 
  •  

سؤال

هذه متابعة ل:
MySQL - هل من الممكن الحصول على جميع العناصر الفرعية في التسلسل الهرمي؟

لدي عمق تعسفي نموذج قائمة المجاورة الجدول (أنا في النقطة التي أنا يستطيع تحويله إلى أ نموذج مجموعة متداخلة.

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

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


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

الطرق الثلاث التي أراها هي:

  1. أنشأت إجراء مخزن الذي من شأنه أن يقوم باستعلام متكرر يعيد جميع الأطفال.

  2. تحويل إلى نموذج مجموعة متداخلة والتي تتطلب الدخول في التعقيدات وربما إنشاء إجراء مخزن لإضافة وتحرير وحذف ذلك.

  3. إنشاء جدول الأجداد الموضحة أعلاه على إدراج/حذف المشغلات للتعامل مع جميع البيانات.

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

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

المحلول

Quassnoi قام بتشغيل بعض اختبارات الأداء على نموذج المجموعات المتداخلة ونموذج قائمة المجاورة وتوثيق النتائج والتوصيات في منشور مدونته قائمة المجاورة مقابل مجموعات متداخلة: MySQL. الملخص التنفيذي هو:

  • مجموعات متداخلة أسرع لجلب جميع العقد الفرعية أو جميع العقد الأم.
  • مجموعات متداخلة هي فكرة سيئة إذا كنت بحاجة إلى تحديث الجدول بشكل متكرر.

هذا هو الاستنتاج من مقالته:

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

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

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

هذا يتطلب إنشاء وظيفة للاستعلام عن الجدول.

يوضح بقية المقالة كيفية تحديد الجدول وتنفيذ الاستعلامات ويعطي قياسات الأداء. يعد استخدام الفهرس المكاني فكرة ذكية لتحسين أداء نموذج المجموعة المتداخلة التي قد تكون جديدة بالنسبة لك.


إذا كنت تفكر أيضًا في الأساليب بدون MySQL ، فقد ترغب في النظر إليها postgresql وهي قاعدة بيانات أخرى مجانية ومفتوحة المصدر. PostgreSQL يدعم الاستعلامات العودية في شكل تعبيرات الجدول المشتركة العودية مما يجعل الاستعلام عن البيانات الوحيدة أسهل من MySQL وأيضًا تقديم أداء أفضل. كتب Quassnoi أيضًا مقالًا قائمة المجاورة مقابل مجموعات متداخلة: postgresql هذا يدل على التفاصيل.

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

SELECT *
FROM yourtable
START WITH id = 42
CONNECT BY parent = PRIOR id

نصائح أخرى

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

فقط لإعطائك مثالًا من المقالة أعلاه:

SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4
FROM category AS t1
LEFT JOIN category AS t2 ON t2.parent = t1.category_id
LEFT JOIN category AS t3 ON t3.parent = t2.category_id
LEFT JOIN category AS t4 ON t4.parent = t3.category_id
WHERE t1.name = 'ELECTRONICS';

+-------------+----------------------+--------------+-------+
| lev1        | lev2                 | lev3         | lev4  |
+-------------+----------------------+--------------+-------+
| ELECTRONICS | TELEVISIONS          | TUBE         | NULL  |
| ELECTRONICS | TELEVISIONS          | LCD          | NULL  |
| ELECTRONICS | TELEVISIONS          | PLASMA       | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS  | FLASH |
| ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS   | NULL  |
| ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL  |
+-------------+----------------------+--------------+-------+
6 rows in set (0.00 sec)

SQL Wise ، لا أعتقد أنه يمكن أن تحصل على أي أجمل وأبسط ؛)

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

ربما يجب أن تفكر في استخدام قاعدة بيانات موجهة نحو المستندات مثل mongodb. يمكن أن يجعل حياتك أسهل بكثير.

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

نظرًا لأن عمليات البحث عن أكوام الذاكرة (memcache ، redis ، إلخ) ، تكون أسرع بكثير من SQL للبسيط id -> data قرارات ، أود استخدامها لتخزين قائمة بتعريفات الأطفال المباشرين لكل عقدة. وبهذه الطريقة ، يمكنك الحصول على أداء لائق عبر خوارزمية متكررة لإنشاء قائمة كاملة لأي عقدة.

لإضافة/حذف عقدة جديدة ، ستحتاج فقط إلى إبطال ذاكرة التخزين المؤقت للوالدين المباشر O(1).

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

إذا كنت تستخدم نموذج التخزين المؤقت الأكثر تقدماً ، فستحتاج إلى ملاحظة أن قوائم عقدة الأطفال الكاملة هذه ستحتاج إلى إبطالها عند تغيير أي من الأطفال O(log n).

بمجرد أن يكون لديك قائمة معرف الأطفال ، يمكنك استخدام SQL's WHERE id IN( id1, id2, .... ) بناء الجملة للاستعلام عن ما تريد.

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

لذا ، بدلاً من تضمين المنطق والعمليات داخل القيود المفروضة على MySQL ، فكر في ضرب الكود للقيام بما تريد ، والاعتماد على MySQL فقط لأدنى مستوى يحصل/وضع.

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