سؤال

بين utf8_general_ci و utf8_unicode_ci, هل هناك أي اختلافات من حيث الأداء ؟

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

المحلول

هاتان المجموعةان كلاهما لترميز الأحرف UTF-8. الاختلافات هي في كيفية فرز النص ومقارنتها.

ملاحظة: منذ MySQL 5.5.3 يجب عليك استخدامها utf8mb4 بدلا من utf8. وبعد كلاهما يشير إلى ترميز UTF-8، ولكن الأكبر سنا utf8 كان لديه قيود خاصة بالحيوية التي تمنع استخدام الأحرف المرقمة أعلاه 0xFFFD.

الاختلافات الرئيسية

  • utf8mb4_unicode_ci يستند إلى قواعد Unicode الرسمية للفرز والمقارنة الشاملة، والتي فرز بدقة في مجموعة واسعة من اللغات.

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

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

ملاحظة: هناك الآن نسخة محدثة من utf8mb4_unicode_ci مسمى utf8mb4_0900_ai_ci - هذا يعتمد على التغييرات في إصدار Unicode 9.0، وهو أيضا أسرع على ما يبدو. وهي تعتمد مخطط تسمية جديد بموجبه 0900 هو إصدار يونيكود و ai يعني بلونات غير حساسة - مثل السابق utf8mb4_unicode_ci, ، فإن لهجات الحروف لا تعتبر مهمة.

فوائد utf8mb4_unicode_ci على utf8mb4_general_ci

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

بقدر اللغات اللاتينية (أي "الأوروبية") تذهب لغات، لا يوجد فرق كبير بين فرز يونيكود والمبسط utf8mb4_general_ci الفرز في MySQL، ولكن لا يزال هناك عدد قليل من الاختلافات:

  • للحصول على أمثلة، فرز ترتيب Unicode "ß" مثل "SS"، و "" مثل "OE" كما يريد الأشخاص الذين يستخدمون هذه الأحرف عادة، في حين utf8mb4_general_ci يفرزهم كحخصيات واحدة (يفترض أن "S" و "E" على التوالي).

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

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

ماذا يجب أن تستخدم؟

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

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

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

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

ماذا تعني الأجزاء

أولا، ci هو ل حالة الأحرف الفرز والمقارنة. هذا يعني أنه مناسب للبيانات النصية، والحالة ليست مهمة. الأنواع الأخرى من الترتيب هي cs (حساسة لحالة الأحرف) للبيانات النصية حيث تكون القضية مهمة، و bin, ، حيث يحتاج الترميز إلى المباراة، قليلا مقابل قليلا، وهو مناسب للحقول التي يتم تشفيرها بالفعل بيانات ثنائية (بما في ذلك، على سبيل المثال، Base64). يؤدي الفرز الحساس لحالة الأحوال إلى بعض النتائج الغريبة ويمكن أن تؤدي المقارنة الحساسة لحالة الأحوال إلى تختلف قيم مكررة فقط في حالة الحرف فقط، لذلك تتخلص مجموعات حساسة لحالة الأحرف عن صالح البيانات النصية - إذا كانت الحالة مهمة بالنسبة لك، فذلك بطريقة ترقيم غير ذلك وبالتالي، ربما يكون الأمر أيضا كبيرا، وقد يكون الترتيب الثنائي أكثر ملاءمة.

التالي، unicode أو general يشير إلى قواعد الفرز والمقارنة المحددة - على وجه الخصوص، يتم تطبيع نص النص أو مقارنة. هناك العديد من مجموعات القواعد المختلفة لترميز حرف UTF8MB4، مع unicode و general كونهما يحاولان العمل جيدا في جميع اللغات الممكنة بدلا من واحد محدد. الاختلافات بين هاتين المجموعتين من القواعد هي موضوع هذه الإجابة. لاحظ أن مجموعات القاعدة الأحدث تشمل 0900 في اشارة الى Unicode 9.0، و unicode_520 في اشارة الى Unicode 5.2.

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

نصائح أخرى

أردت أن أعرف ما هو الفرق في الأداء بين استخدام utf8_general_ci و utf8_unicode_ci, ولكن لم أجد أي المعايير المدرجة على الإنترنت, لذا قررت إنشاء معايير نفسي.

أنا خلقت الجدول بسيط جدا مع 500 ، 000 الصفوف:

CREATE TABLE test(
  ID INT(11) DEFAULT NULL,
  Description VARCHAR(20) DEFAULT NULL
)
ENGINE = INNODB
CHARACTER SET utf8
COLLATE utf8_general_ci;

ثم ملأت مع بيانات عشوائية عن طريق تشغيل هذا الإجراء المخزن:

CREATE PROCEDURE randomizer()
BEGIN
  DECLARE i INT DEFAULT 0;
  DECLARE random CHAR(20) ;
  theloop: loop
    SET random = CONV(FLOOR(RAND() * 99999999999999), 20, 36);
    INSERT INTO test VALUES (i+1, random);
    SET i=i+1;
    IF i = 500000 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END

ثم إنشاء الإجراءات المخزنة التالية لقياس بسيطة SELECT, SELECT مع LIKE, و الفرز (SELECT مع ORDER BY):

CREATE PROCEDURE benchmark_simple_select()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE Description = 'test' COLLATE utf8_general_ci;
    SET i = i + 1;
    IF i = 30 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

CREATE PROCEDURE benchmark_select_like()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE Description LIKE '%test' COLLATE utf8_general_ci;
    SET i = i + 1;
    IF i = 30 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

CREATE PROCEDURE benchmark_order_by()
BEGIN
  DECLARE i INT DEFAULT 0;
  theloop: loop
    SELECT *
    FROM test
    WHERE ID > FLOOR(1 + RAND() * (400000 - 1))
    ORDER BY Description COLLATE utf8_general_ci LIMIT 1000;
    SET i = i + 1;
    IF i = 10 THEN
      LEAVE theloop;
    END IF;
  END LOOP theloop;
END;

في الإجراءات المخزنة فوق utf8_general_ci يتم استخدام ترتيب ، ولكن بالطبع خلال الاختبارات اعتدت على حد سواء utf8_general_ci و utf8_unicode_ci.

لقد دعوت كل الإجراء المخزن 5 مرات لكل الترتيب (5 مرات utf8_general_ci و 5 مرات utf8_unicode_ci) ومن ثم حساب متوسط القيم.

النتائج هي:

benchmark_simple_select()

  • مع utf8_general_ci:9,957 ms
  • مع utf8_unicode_ci:10,271 ms

في هذا المعيار باستخدام utf8_unicode_ci أبطأ من utf8_general_ci بنسبة 3.2%.

benchmark_select_like()

  • مع utf8_general_ci:11,441 ms
  • مع utf8_unicode_ci:12,811 ms

في هذا المعيار باستخدام utf8_unicode_ci أبطأ من utf8_general_ci بنسبة 12%.

benchmark_order_by()

  • مع utf8_general_ci:11,944 ms
  • مع utf8_unicode_ci:12,887 ms

في هذا المعيار باستخدام utf8_unicode_ci أبطأ من utf8_general_ci بنسبة 7.9%.

هذا المشنور يصفها بشكل جيد للغاية.

باختصار: يستخدم UTF8_Unicode_ci خوارزمية تجميع Unicode كما هو محدد في معايير Unicode، بينما utf8_general_ci هو ترتيب فرز أكثر بساطة ينتج عنه نتائج الفرز "أقل دقة".

انظر دليل MySQL، مجموعات أحرف Unicode. الجزء:

بالنسبة لأي مجموعة أحرف Unicode، تكون العمليات التي يتم تنفيذها باستخدام Tradation _general_ci أسرع من أولئك من أجل تجميع _unicode_ci. على سبيل المثال، فإن المقارنات الخاصة ب Outf8_general_ci Collation أسرع، ولكن أقل صحة قليلا، من المقارنات الخاصة ب Outf8_unicode_ci. السبب في ذلك هو أن UTF8_Unicode_ci يدعم تعيينات مثل التوسعات؛ وهذا هو، عندما تقارن حرف واحد مساويا لمجموعات الأحرف الأخرى. على سبيل المثال، باللغة الألمانية وبعض اللغات الأخرى "ß" تساوي "SS". يدعم UTF8_unicode_ci أيضا الانقباضات والأحرف الجاهلة. utf8_general_ci هو ترتيب قديم لا يدعم التوسعات أو الاقاضنات أو الأحرف الجاهزة. يمكن أن تجعل مقارنات واحدة إلى واحدة فقط بين الشخصيات.

لذلك لتلخيص، يستخدم UTF_General_ci أصغر وأقل صحيحا (وفقا لمجموعة المقارنات القياسية) من UTF_UNICODE_CI التي ينبغي تنفيذ المعيار بأكمله. ستكون مجموعة General_ci أسرع لأن هناك حساب أقل للقيام به.

كلمات موجزة:

إذا كنت بحاجة إلى ترتيب فرز أفضل - استخدم utf8_unicode_ci (هذا هو الأسلوب المفضل)،

ولكن إذا كنت مهتما تماما بالأداء - استخدم utf8_general_ci, ، ولكن أعرف أنها قديمة قليلا.

الاختلافات من حيث الأداء طفيفة جدا.

بعض التفاصيل (PL)

كما يمكننا القراءة هنا (بيتر جولوتزان) هناك اختلاف في فرز / مقارنة الحرف البولندي "" (L مع السكتة الدماغية - HTML ESC: Ł) (الحالة الصغيرة: "ł" - HTML ESC: ł) - لدينا اتباع الافتراض:

utf8_polish_ci      Ł greater than L and less than M
utf8_unicode_ci     Ł greater than L and less than M
utf8_unicode_520_ci Ł equal to L
utf8_general_ci     Ł greater than Z

في خطاب اللغة البولندية Ł هو بعد الرسالة L و قبل M. وبعد لا أحد من هذا الترميز أفضل أو أسوأ - يعتمد ذلك على احتياجاتك.

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