it-swarm.asia

ما هو الترتيب الافتراضي لسجلات عبارة SELECT في MySQL؟

افترض أن لديك الجدول والبيانات التالية:

create table t (
    k int,
    v int,
    index k(k)
    ) engine=memory;

insert into t (k, v)
values (10, 1),
       (10, 2),
       (10, 3);

عند إصدار select * from t where k = 10 مع عدم وجود order by_ جملة ، كيف يقوم MySQL بفرز السجلات بشكل افتراضي؟

76
daisy

إعادة النشر إجابتي على سؤال مماثل بخصوص SQL Server:

في عالم SQL ، لا يعد الترتيب خاصية متأصلة لمجموعة من البيانات. وبالتالي ، لا تحصل على أي ضمانات من RDBMS الخاصة بك بأن بياناتك ستعود في ترتيب معين - أو حتى في ترتيب ثابت - إلا إذا قمت بالاستعلام عن بياناتك باستخدام بند ORDER BY.

لذا ، للإجابة على سؤالك:

  • يقوم MySQL بفرز السجلات إلا أنه يريد ذلك دون أي ضمان للاتساق.
  • إذا كنت تنوي الاعتماد على هذا الطلب لأي شيء ، يجب عليك تحديد طلبك المطلوب باستخدام ORDER BY. القيام بأي شيء آخر هو إعداد نفسك لمفاجآت غير مرحب بها.

هذه خاصية لجميع SQL ، وليس فقط MySQL. النص ذو الصلة في مواصفات SQL-92 هو:

إذا لم يتم تحديد <order by clause> ، فإن ترتيب صفوف Q يعتمد على التنفيذ.

هناك أجزاء مماثلة من النص في المواصفات الخاصة بالمؤشرات.

87
Nick Chammas

ترتيب الصفوف في غياب ORDER BY قد يكون بند:

  • تختلف بين أي محركي تخزين ؛
  • إذا كنت تستخدم نفس محرك التخزين ، فقد يكون مختلفًا بين أي نسختين من نفس محرك التخزين ؛ مثال هنا ، قم بالتمرير لأسفل إلى "ترتيب الصفوف".
  • إذا كان إصدار محرك التخزين هو نفسه ، ولكن إصدار MySQL مختلف ، فقد يكون مختلفًا بسبب تغييرات محسن الاستعلام بين هذه الإصدارات ؛
  • إذا كان كل شيء هو نفسه ، فقد يكون مختلفًا بسبب طور القمر وهذا جيد.
29
Laurynas Biveinis

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

بيانات فعلية ، فوضوية في التخزين. الفهرس المرتبط بالبيانات ، مطلوب في التخزين والبناء. يعتمد السحب الفعلي للبيانات ، مرتبة أو غير مرتبة ، على الاستعلام المعني.

11
James Pulley

عندما يتعلق الأمر بمحرك التخزين ( MEMORY ، أتوقع أن يكون الطلب حسب ترتيب الإدراج لأن الفهرس الافتراضي التخطيط HASH بدلاً من BTREE ولا يتم استخدام أي جانب من جوانب تخطيط الفهرس. نظرًا لأنك قمت بفهرسة k ، و k هي نفس القيمة ، تدخل جميع المفاتيح في علبة التجزئة نفسها . نظرًا لعدم وجود سبب لافتراض التعقيد الإضافي لملء دلو التجزئة ، فإن ترتيب الإدراج يكون منطقيًا.

أخذت نفس نموذج الجدول والبيانات وركضت 30 INSERTs وحصلت على هذا:

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.00 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

قررت اختبار إضافة قيمتين مختلفتين لـ k: 10 و 11 حصلت على هذا:

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t values
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

يبدو ترتيب الإدراج. ك = 11 تم تجزئة المفتاح الأول ثم 10. ماذا عن إدراج 10 أولاً بدلاً من 11؟ هذا ما حصلت عليه:

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

إنه بالإجماع !!! أمر الإدراج هو الجواب.

ملاحظات جانبية على استخدام الفهارس لمحرك التخزين MEMORY

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

عند إنشاء فهرس ، يمكنك تحديد USING BTREE جملة مع تعريف الفهرس. سيؤدي هذا إلى تحسين الأشياء لاستعلامات النطاق.

سيؤدي البحث عن صف معين إلى تحقيق نفس النتيجة في الأداء إما مع HASH أو BTREE.

تحديث 2011-09-22 11:18 بتوقيت شرق الولايات المتحدة

تعلمت شيئًا مثيرًا للاهتمام اليوم. قرأت الرابط المقدم بواسطة @ Laurynas Biveinis من بيركونا: رابط بيرسونا يقول شيئًا عن جداول الذاكرة لـ MySQL 5.5.15:

ترتيب الصفوف

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

كان هذا رابطًا جيدًا بالنسبة لي اليوم. أظهرت الإجابة التي قدمتها أنه تم استرداد الجدول الذي قمت بتحميله حتى أتوقع اليوم في MySQL 5.5.12. كما أشار للتو بيرسونا و @ Laurynas Biveinis ، لا يوجد ضمان في إصدار ثانوي آخر.

لذا ، بدلاً من محاولة الدفاع عن إجابتي ، أفضل الترويج للإجابة من @ Laurynas Biveinis لأنها أحدث المعلومات. مجد القبعات والقبعات لـ @ Laurynas Biveinis . أود أيضًا أن أشكر @ eevar للإشارة بأدب إلى عدم الترويج للإجابات الخاصة بالإصدارات على الأسئلة. كلاهما يحصل على تصويتي اليوم.

5
RolandoMySQLDBA