ما الفرق بين utf8_general_ci و utf8_unicode_ci
-
12-09-2019 - |
سؤال
بين 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
. وبعد لا أحد من هذا الترميز أفضل أو أسوأ - يعتمد ذلك على احتياجاتك.