الخوارزمية المستخدمة لإجراء الإزاحة/الحد على مجموعة النتائج الموحدة

dba.stackexchange https://dba.stackexchange.com/questions/103223

سؤال

لدي مجموعتان من النتائج:

rs1:

     id       name
   serial     text
________________
     1        Nick
....................
  1233112     Pete

rs2:

     id       name
   serial     text
________________
  123121      Mike
....................
 221233112   Junior

إذا كتبنا استعلامًا:

SELECT *
FROM
(

    SELECT *
    FROM rs1

    UNION ALL

    SELECT *
    FROM rs2

) as rs
OFFSET 100000 LIMIT 10;

كيف يتم حساب نتيجة الاستعلام؟ما هي الخوارزمية التي سيتم استخدامها؟

أعتقد أن الخادم يقوم بإجراء تقييم كسول بمعنى عدم تحميل الاتحاد بأكمله والتكرار عليه ثم إرجاع النتيجة المطلوبة.

سأكون سعيدًا إذا وصفت الخوارزميات المستخدمة في خوادم SQL الأخرى كإضافة.

محدث:أنا جديد تمامًا في التعامل مع قواعد البيانات الداخلية ولا أعرف ما إذا كان من الممكن سؤال خادم SQL نفسه عن خطة تنفيذ الاستعلام.

فيما يلي خطة الاستعلام:

"Limit  (cost=77.11..77.88 rows=10 width=522)"
"  ->  Append  (cost=0.00..140.18 rows=1818 width=522)"
"        ->  Seq Scan on tbl  (cost=0.00..70.09 rows=909 width=522)"
"        ->  Seq Scan on tbl tbl_1  (cost=0.00..70.09 rows=909 width=522)"

استعلام saqme بالترتيب حسب المعرف:

"Limit  (cost=33.16..36.42 rows=10 width=522)"
"  ->  Merge Append  (cost=0.56..593.16 rows=1818 width=522)"
"        Sort Key: tbl.id"
"        ->  Index Scan Backward using pk_tabl on tbl (cost=0.28..285.21 rows=909 width=522)"
"        ->  Index Scan Backward using pk_tbl on tbl tbl_1  (cost=0.28..285.21 rows=909 width=522)"
هل كانت مفيدة؟

المحلول

عند الحد من الجمل مثل OFFSET يتم تطبيقها بناءً على الاستعلام، وخاصةً ما يتم ترتيب النتيجة به.

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

ل UNION الاستعلام من تلقاء نفسه، فهو يعتمد على العقول الموجودة في مخطط الاستعلام، لذا قد يتعين عليك إلقاء نظرة على مخرجات خطته لتعرف (أنا لست خبيرًا في Postgres)، ومرة ​​أخرى قد يعتمد على بقية تفاصيل الاستعلام.ومع ذلك تم إنجاز العمل (مما سيؤثر على الأداء) فإن الإخراج سيكون هو نفسه بالرغم من ذلك:سيتم تطبيق القيد على النتيجة الكاملة.

في المثال الذي تعطيه UNION الاستعلام يوفر في الواقع جدولًا مشتقًا، اسمه rs.سيتم بالتأكيد تطبيق القيد على النتيجة بأكملها هنا بحيث تكون وظيفيًا كما لو كنت قد فعلت ذلك SELECT * FROM <some_table> OFFSET 100000 LIMIT 10.نظرًا لأنهما متماثلان، يمكنك إعادة كتابة المثال الخاص بك ببساطة:

SELECT * FROM rs1
UNION ALL
SELECT * FROM rs2
OFFSET 100000 LIMIT 10;

وستكون النتائج هي نفسها.

ملاحظة هامة:لم تحددها أي شرط الطلب هنا.قد يكون هذا لأنك تعطي مثالاً بسيطًا، لذا سامحني إذا كنت أخبرك بشيء تعرفه بالفعل، ولكن بدون شرط الطلب، يجب أن تفترض أن ترتيب الإخراج عشوائي، وربما عشوائي، ومن المحتمل أن يتغير بين عمليات تشغيل نفس الاستعلام.في بعض الأحيان يكون هذا أمرًا جيدًا (أنت فقط تريد البيانات ولا تهتم بالترتيب) ولكن بمجرد استخدام أشياء مثل OFFSET/LIMIT/TOP/...أنت تهتم بالأمر لأن الاستعلام بعده OFFSET 10000 LIMIT 10 ومن المرجح أن يكون OFFSET 10010 LIMIT 10 وتريد أن تريد بالتأكيد عشرة صفوف مختلفة حسب بعض الترتيب (ليست عشرة صفوف عشوائية يمكن من الناحية النظرية أن تكون هي نفس العشرة التي كانت في المرة الأخيرة).في الممارسة العملية، ترتيب الإخراج هو عادة أكثر استقرارًا من هذا، لكنه ليس كذلك دائمًا بأي حال من الأحوال، لذا يجب عليك دائمًا تقديم جملة طلب إذا كان التغيير المفاجئ في ترتيب الإخراج قد يتسبب في سلوك غير مرغوب فيه.

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