حد عملي لطول استعلام SQL (على وجه التحديد MySQL)

هل من السيئ بشكل خاص أن يكون لديك استعلام SQL كبير جدًا مع الكثير من جمل WHERE (التي يمكن أن تكون مكررة)؟

على سبيل المثال ، إليك طلب بحث تم إنشاؤه من تطبيق الويب الخاص بي مع إيقاف تشغيل كل شيء ، وهو ما ينبغي أن يكون أكبر طلب بحث ممكن لهذا البرنامج لإنشاء:

SELECT * 
FROM 4e_magic_items 
INNER JOIN 4e_magic_item_levels 
  ON 4e_magic_items.id = 4e_magic_item_levels.itemid 
INNER JOIN 4e_monster_sources 
  ON 4e_magic_items.source = 4e_monster_sources.id 
WHERE (itemlevel BETWEEN 1 AND 30)  
  AND source!=16 AND source!=2 AND source!=5 
  AND source!=13 AND source!=15 AND source!=3 
  AND source!=4 AND source!=12 AND source!=7 
  AND source!=14 AND source!=11 AND source!=10 
  AND source!=8 AND source!=1 AND source!=6 
  AND source!=9  AND type!='Arms' AND type!='Feet' 
  AND type!='Hands' AND type!='Head' 
  AND type!='Neck' AND type!='Orb' 
  AND type!='Potion' AND type!='Ring' 
  AND type!='Rod' AND type!='Staff' 
  AND type!='Symbol' AND type!='Waist' 
  AND type!='Wand' AND type!='Wondrous Item' 
  AND type!='Alchemical Item' AND type!='Elixir' 
  AND type!='Reagent' AND type!='Whetstone' 
  AND type!='Other Consumable' AND type!='Companion' 
  AND type!='Mount' AND (type!='Armor' OR (false )) 
  AND (type!='Weapon' OR (false )) 
 ORDER BY type ASC, itemlevel ASC, name ASC

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

0
وأضاف تحرير
الآراء: 1
1. شكرا لإجابتك على السؤال ، أعتقد أن حجم الاستعلام لا ينبغي أن يكون مشكلة بالنسبة لي الآن. 2. شكرا لكم جميعا على النصائح حول تنسيق SQL. أنا جديد في ذلك وهناك الكثير من الحيل التي لا أعرفها (على سبيل المثال "اكتب ليس في (...)") 3. فقط كإضافة ، هذا تطبيق PHP/MySQL
وأضاف المؤلف Asmor, مصدر
في ما يلي مُنسق SQL مفيد عبر الإنترنت: sqlinform.com
وأضاف المؤلف micahwittman, مصدر
عندما تحاول استخدام موقع الويب ، هل يبدو بطيئًا؟ إذا كان هناك بضع مئات من الزيارات في اليوم ، أعتقد أنك لا تستطيع أن تقلق بشأنها. هل تتوقع زيادة حركة المرور؟ بكم؟ إذا لم تكن مضطرًا للوقت ، يمكنك القيام بذلك ، لإثبات الموقع في المستقبل. ولكن بعد ذلك ، هو الوقت الذي يستغرقه البحث عن الإزاحات الاحتياطية وإزالتها بشكل أكبر من الوقت الذي يستغرقه تشغيل الاستعلام فقط؟
وأضاف المؤلف Matt Blaine, مصدر

6 إجابة

قراءة الاستعلام الخاص بك يجعلني أرغب في لعب آر بي جي.

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

لقد عملت مع بعض الاستعلامات التي تتكون من أكثر من 1000 سطر ، وهذا صعب التصحيح.

بالمناسبة ، هل يمكنني اقتراح نسخة معدلة؟ هذا في الغالب لإثبات أهمية التنسيق. أنا على ثقة بأن هذا سيكون أسهل في الفهم.

select *  
from
  4e_magic_items mi
 ,4e_magic_item_levels mil
 ,4e_monster_sources ms
where mi.id = mil.itemid
  and mi.source = ms.id
  and itemlevel between 1 and 30
  and source not in(16,2,5,13,15,3,4,12,7,14,11,10,8,1,6,9)  
  and type not in(
                  'Arms' ,'Feet' ,'Hands' ,'Head' ,'Neck' ,'Orb' ,
                  'Potion' ,'Ring' ,'Rod' ,'Staff' ,'Symbol' ,'Waist' ,
                  'Wand' ,'Wondrous Item' ,'Alchemical Item' ,'Elixir' ,
                  'Reagent' ,'Whetstone' ,'Other Consumable' ,'Companion' ,
                  'Mount'
                 )
  and ((type != 'Armor') or (false))
  and ((type != 'Weapon') or (false))
order by
  type asc
 ,itemlevel asc
 ,name asc

/*
Some thoughts:
==============
0 - Formatting really matters, in SQL even more than most languages.
1 - consider selecting only the columns you need, not "*"
2 - use of table aliases makes it short & clear ("MI", "MIL" in my example)
3 - joins in the WHERE clause will un-clutter your FROM clause
4 - use NOT IN for long lists
5 - logically, the last two lines can be added to the "type not in" section.
    I'm not sure why you have the "or false", but I'll assume some good reason
    and leave them here.
*/
0
وأضاف
لثاني فكرة ديفيد باء ... تجربتي هي في الغالب خوادم Oracle/SQL ، وكلاهما لا يعاني من القيود التي أثارها Aeon. إذا كان MySql بالفعل يتصرف بهذه الطريقة ، فإنك بالتأكيد تريد الاحتفاظ بالارتباطات في FROM. أقترح تجربة كلتا الطريقتين ومقارنة أوقات التنفيذ.
وأضاف المؤلف JosephStyons, مصدر
هذا لأن الدروع (والأسلحة) يتم ترشيحها حسب النوع. على سبيل المثال ، إذا تم اختيار القماش والإخفاء ، فسيتم قراءة ما يلي: (type! = 'Armor' OR (FALSE OR restrictions like 'C' OR restrictions like 'H')) تضيف الصفحة "أو قيود مثل" أيا كان " "داخل الأهل ، هناك حاجة لذلك كاذبة.
وأضاف المؤلف Asmor, مصدر
الصلات في جملة FROM لن تقوم بترتيب جملة WHERE الخاصة بك. Aeon - يجب ألا يكون هناك فرق في الأداء مع مُحسِّن طلبات البحث المناسب. هو MySQL بهذا السوء؟
وأضاف المؤلف Amy B, مصدر
سوف ينضم في الواقع تسريع الأمور ، لا سيما مع المؤشرات المناسبة. والسبب هو أنه إذا كانت جميع البنود الخاصة بك موجودة في WHERE ، فسوف يقوم MySQL بجلب جميع البيانات ، ثم ترشيحها ؛ في حين أنه مع وجود صلة مناسبة فإنه سيتم فقط اختيار البيانات المطلوبة ، والتي يمكن أن تكون بعض الطلبات من حجم أصغر - أسرع لتصفية.
وأضاف المؤلف Aeon, مصدر
أوه ، و ... ما لم أفقد شيئًا ما ، (اكتب! = "درع" أو (خطأ)) سيُقيّم إما صوابًا أو كاذبًا ، ولكن في الحالتين لن يؤثر على مجموعة النتائج ، انها حقا ليست هناك حاجة حتى.
وأضاف المؤلف Aeon, مصدر
downvote لـ cluttering جملة WHERE مع شروط JOIN.
وأضاف المؤلف longneck, مصدر

أفترض أنك تعني بـ "تم إيقاف" أن أي حقل ليس له قيمة؟

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

0
وأضاف

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

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

0
وأضاف

الحد الافتراضي لوحدة خدمة MySQL 5.0 هو " 1 ميغابايت " ، القابل للتهيئة حتى 1 غيغابايت.

تم تكوين هذا عبر إعداد max_allowed_packet العميل والخادم ، والحد الفعال هو المؤجر من الاثنين.

المحاذير:

  • من المرجح أن هذا الحد "الحزمة" لا يعين مباشرة إلى أحرف في جملة SQL. من المؤكد أنك تريد أن تأخذ في الاعتبار ترميز الأحرف داخل العميل ، وبعض البيانات الوصفية للحزمة ، وما إلى ذلك)
0
وأضاف

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

قد تختلف الأميال الخاصة بك ، وهناك بعض الاستعلامات طويلة بشكل استثنائي التي لديها سبب وجيه ليكون. لكن القاعدة الأساسية هي 10 سطور.

Example (mildly improper SQL):

SELECT x, y, z
FROM a, b
WHERE fiz = 1
AND foo = 2
AND a.x = b.y
AND b.z IN (SELECT q, r, s, t
            FROM c, d, e
            WHERE c.q = d.r
              AND d.s = e.t
              AND c.gar IS NOT NULL)
ORDER BY b.gonk

هذا على الارجح كبير جدا. ومع ذلك ، فإن التحسين ، يعتمد إلى حد كبير على السياق.

فقط تذكر ، كلما كان الاستعلام أطول وأكثر تعقيدًا ، كلما زادت صعوبة الحفاظ عليه.

0
وأضاف

وSELECTglobal.max_allowed_packet

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

0
وأضاف