سؤال

أنا أتساءل عما إذا كان هناك "أفضل" الاختيار ترتيب النسخ في الخلية على الموقع العام حيث لم تكن متأكدا 100 ٪ من ما سوف يكون من دخلت ؟ أنا أفهم أن جميع ترميزات يجب أن يكون نفسه ، مثل MySQL, Apache, HTML و أي شيء داخل PHP.

في الماضي كنت قد وضعت PHP إلى الإخراج في "UTF-8" ، ولكن الذي جمع لا هذه المباراة في الخلية ؟ أعتقد أنه واحد من UTF-8 منها ، ولكن لقد استخدمت utf8_unicode_ci, utf8_general_ci, ، utf8_bin قبل.

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

المحلول

والفرق الرئيسي هو الفرز دقة (عند المقارنة بين الأحرف في اللغة) والأداء. وutf8_bin واحدة خاصة الوحيد الذي هو للمقارنة بين الحروف في شكل ثنائي.

وutf8_general_ci أسرع إلى حد ما من utf8_unicode_ci، ولكن أقل دقة (للفرز). و<م> لغة معينة UTF8 الترميز (مثل utf8_swedish_ci) تتضمن قواعد اللغة الإضافية التي تجعلها أكثر دقة لفرز لتلك اللغات. معظم الوقت يمكنني استخدام utf8_unicode_ci (انا افضل الدقة لتحسين الأداء صغيرة)، ما لم يكن لدي سبب وجيه لتفضيل لغة معينة.

ويمكنك قراءة المزيد عن حرف unicode معين يحدد على دليل ماي - <وأ href = "http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html" يختلط = "noreferrer"> http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-sets.html

نصائح أخرى

وكن جدا، حذرا جدا في هذه المشكلة التي يمكن أن تحدث عند استخدام utf8_general_ci.

سوف

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

وهذه المشكلة تفضح نفسها على أقل تقدير في 5.x إصدارات مبكرة - أنا لست متأكدا إذا كان هذا السلوك كما تغير لاحقا

وأنا لا DBA، ولكن لتجنب هذه المشكلة، وأنا دائما الذهاب مع utf8-bin بدلا من واحد لحالة الأحرف.

ويصف النصي أدناه المشكلة عن طريق المثال.

-- first, create a sandbox to play in
CREATE DATABASE `sandbox`;
use `sandbox`;

-- next, make sure that your client connection is of the same 
-- character/collate type as the one we're going to test next:
charset utf8 collate utf8_general_ci

-- now, create the table and fill it with values
CREATE TABLE `test` (`key` VARCHAR(16), `value` VARCHAR(16) )
    CHARACTER SET utf8 COLLATE utf8_general_ci;

INSERT INTO `test` VALUES ('Key ONE', 'value'), ('Key TWO', 'valúe');

-- (verify)
SELECT * FROM `test`;

-- now, expose the problem/bug:
SELECT * FROM test WHERE `value` = 'value';

--
-- Note that we get BOTH keys here! MySQLs UTF8 collates that are 
-- case insensitive (ending with _ci) do not distinguish between 
-- both values!
--
-- collate 'utf8_bin' doesn't have this problem, as I'll show next:
--

-- first, reset the client connection charset/collate type
charset utf8 collate utf8_bin

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Note that we get just one key now, as you'd expect.
--
-- This problem appears to be specific to utf8. Next, I'll try to 
-- do the same with the 'latin1' charset:
--

-- first, reset the client connection charset/collate type
charset latin1 collate latin1_general_ci

-- next, convert the values that we've previously inserted
-- in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET latin1 COLLATE latin1_general_ci;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Again, only one key is returned (expected). This shows 
-- that the problem with utf8/utf8_generic_ci isn't present 
-- in latin1/latin1_general_ci
--
-- To complete the example, I'll check with the binary collate
-- of latin1 as well:

-- first, reset the client connection charset/collate type
charset latin1 collate latin1_bin

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET latin1 COLLATE latin1_bin;

-- now, re-check for the bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Again, only one key is returned (expected).
--
-- Finally, I'll re-introduce the problem in the exact same 
-- way (for any sceptics out there):

-- first, reset the client connection charset/collate type
charset utf8 collate utf8_generic_ci

-- next, convert the values that we've previously inserted in the table
ALTER TABLE `test` CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

-- now, re-check for the problem/bug
SELECT * FROM test WHERE `value` = 'value';

--
-- Two keys.
--

DROP DATABASE sandbox;

في الواقع, ربما كنت ترغب في استخدام utf8_unicode_ci أو utf8_general_ci.

  • utf8_general_ci أنواع من تجريد جميع لهجات والفرز كما لو كانت ASCII
  • utf8_unicode_ci يستخدم Unicode نوع النظام ، لذلك يفرز بشكل صحيح في أكثر اللغات

ومع ذلك ، إذا كنت تستخدم فقط هذا لتخزين النص الانكليزي, هذه لا تختلف.

فمن الأفضل استخدام مجموعة الأحرف utf8mb4 مع ترتيب utf8mb4_unicode_ci.

مجموعة أحرف ، utf8, يدعم فقط كمية صغيرة من التعليمات البرمجية UTF-8 نقاط عن 6% من الشخصيات المحتملة. utf8 فقط يدعم متعددة اللغات الأساسية الطائرة (BMP).هناك 16 طائرات أخرى.كل طائرة يحتوي على 65,536 الشخصيات. utf8mb4 يدعم جميع 17 الطائرات.

الخلية سيتم اقتطاع 4 بايت UTF-8 أحرف مما أدى إلى تلف البيانات.

على utf8mb4 مجموعة الأحرف قدم في الخلية 5.5.3 على 2010-03-24.

بعض التغييرات المطلوبة إلى استخدام مجموعة الأحرف ليست تافهة:

  • تغييرات قد تحتاج إلى أن تكون في التطبيق الخاص بك قاعدة بيانات محول.
  • التغييرات سوف تحتاج إلى بلدي.cnf ، بما في ذلك تحديد مجموعة الأحرف جمع و تحويل innodb_file_format إلى باراكودا
  • SQL إنشاء البيانات قد تحتاج إلى ما يلي: ROW_FORMAT=DYNAMIC
    • ديناميكية مطلوب مؤشرات على VARCHAR(192) و أكبر.

ملاحظة:التحول إلى Barracuda من Antelope, قد تتطلب إعادة تشغيل خدمة الخلية أكثر من مرة. innodb_file_format_max لا يتغير حتى بعد خدمة الخلية تم إعادة تشغيل إلى: innodb_file_format = barracuda.

MySQL يستخدم القديمة Antelope ك InnoDB تنسيق الملف. Barracuda يدعم ديناميكية صف من الأشكال التي سوف تحتاج إذا كنت لا تريد أن تصل إلى أخطاء SQL لإنشاء فهارس ومفاتيح بعد التبديل إلى محارف: utf8mb4

  • #1709 - مؤشر حجم العمود كبيرة جدا.أقصى حجم العمود هو 767 بايت.
  • #1071 - المفتاح المحدد كانت طويلة جدا ؛ ماكس طول المفتاح هو 767 بايت

السيناريو التالي تم اختبارها على الخلية 5.6.17:بشكل افتراضي, MySQL هو تكوين مثل هذا:

SHOW VARIABLES;

innodb_large_prefix = OFF
innodb_file_format = Antelope

توقف خدمة الخلية و إضافة خيارات القائمة الخاصة بك بلدي.cnf:

[client]
default-character-set= utf8mb4

[mysqld]
explicit_defaults_for_timestamp = true
innodb_large_prefix = true
innodb_file_format = barracuda
innodb_file_format_max = barracuda
innodb_file_per_table = true

# Character collation
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci

مثال SQL إنشاء البيان:

CREATE TABLE Contacts (
 id INT AUTO_INCREMENT NOT NULL,
 ownerId INT DEFAULT NULL,
 created timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 modified timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 contact VARCHAR(640) NOT NULL,
 prefix VARCHAR(128) NOT NULL,
 first VARCHAR(128) NOT NULL,
 middle VARCHAR(128) NOT NULL,
 last VARCHAR(128) NOT NULL,
 suffix VARCHAR(128) NOT NULL,
 notes MEDIUMTEXT NOT NULL,
 INDEX IDX_CA367725E05EFD25 (ownerId),
 INDEX created (created),
 INDEX modified_idx (modified),
 INDEX contact_idx (contact),
 PRIMARY KEY(id)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB ROW_FORMAT=DYNAMIC;
  • يمكنك أن ترى خطأ #1709 إنشاء INDEX contact_idx (contact) إذا ROW_FORMAT=DYNAMIC يتم إزالتها من خلق البيان.

ملاحظة:تغيير المؤشر إلى حدود أول من 128 حرفا على contactيلغي الحاجة إلى استخدام باراكودا مع ROW_FORMAT=DYNAMIC

INDEX contact_idx (contact(128)),

لاحظ أيضا:عندما يقول حجم الحقل VARCHAR(128), هذا ليس 128 بايت.يمكنك استخدام لدينا 128, 4 بايت الشخصيات أو 128, 1 بايت الشخصيات.

هذا INSERT بيان يجب أن تحتوي على 4 بايت 'بو' حرف في الصف 2:

INSERT INTO `Contacts` (`id`, `ownerId`, `created`, `modified`, `contact`, `prefix`, `first`, `middle`, `last`, `suffix`, `notes`) VALUES
(1, NULL, '0000-00-00 00:00:00', '2014-08-25 03:00:36', '1234567890', '12345678901234567890', '1234567890123456789012345678901234567890', '1234567890123456789012345678901234567890', '12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678', '', ''),
(2, NULL, '0000-00-00 00:00:00', '2014-08-25 03:05:57', 'poo', '12345678901234567890', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '', ''),
(3, NULL, '0000-00-00 00:00:00', '2014-08-25 03:05:57', 'poo', '12345678901234567890', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '123💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩', '', '');

يمكنك أن ترى مقدار المساحة المستخدمة من قبل last العمود:

mysql> SELECT BIT_LENGTH(`last`), CHAR_LENGTH(`last`) FROM `Contacts`;
+--------------------+---------------------+
| BIT_LENGTH(`last`) | CHAR_LENGTH(`last`) |
+--------------------+---------------------+
|               1024 |                 128 | -- All characters are ASCII
|               4096 |                 128 | -- All characters are 4 bytes
|               4024 |                 128 | -- 3 characters are ASCII, 125 are 4 bytes
+--------------------+---------------------+

في قاعدة البيانات الخاصة بك محول, قد ترغب في تعيين محارف ترتيب الاتصال الخاص بك:

SET NAMES 'utf8mb4' COLLATE 'utf8mb4_unicode_ci'

في PHP, هذا من شأنه أن يكون تعيين: \PDO::MYSQL_ATTR_INIT_COMMAND

المراجع:

وأساسا، فإنه يعتمد على كيفية التفكير في السلسلة.

وأنا دائما استخدام utf8_bin بسبب مشكلة أبرزها جوس. في رأيي، بقدر ما يجب أن تهتم قاعدة البيانات، سلسلة لا يزال مجرد سلسلة. A السلسلة عددا من UTF-8 أحرف. حرف وتمثيل ثنائي فلماذا أنها لا تحتاج إلى معرفة اللغة التي تستخدمها؟ عادة، والناس سوف يكون بناء قواعد البيانات للأنظمة مع نطاق لمواقع متعددة اللغات. هذا هو بيت القصيد من استخدام UTF-8 كما مجموعة أحرف. أنا قليلا من pureist ولكن أعتقد أن المخاطر علة تفوق بشكل كبير على أفضلية طفيفة قد تحصل على الفهرسة. وينبغي أن يتم أي قواعد اللغوية على مستوى أعلى بكثير من DBMS.

في كتبي "قيمة" لا ينبغي أبدا في مليون سنة مساويا ل"قيمة".

إذا أريد لتخزين حقل نص والقيام بالبحث حساسة القضية، وسوف تستخدم وظائف سلسلة MYSQL مع وظائف PHP مثل LOWER () وظيفة strtolower فب ().

ل UTF-8 معلومات نصية, يجب عليك استخدام utf8_general_ci لأن...

  • utf8_bin:مقارنة سلاسل من قبل ثنائي قيمة كل حرف في السلسلة

  • utf8_general_ci:مقارنة السلاسل باستخدام قواعد اللغة العامة ، باستخدام حالة الأحرف مقارنات

أ.ك.أ.فإنه ينبغي أن يجعل البحث وفهرسة البيانات أسرع/أكثر كفاءة/أكثر فائدة.

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

ولأن utf8_general_ci هو الترتيب الافتراضي للUnicode في الخلية، إذا كنت ترغب في استخدام utf8_unicode_ci ثم ينتهي بك الأمر إلى تحديد ذلك في الكثير من الأماكن.

وعلى سبيل المثال، عن اتصالات العميل ليس فقط لديها محارف الافتراضية (المنطقي بالنسبة لي)، ولكن أيضا ترتيب الافتراضي (أي ترتيب سوف تتخلف دائما إلى utf8_general_ci لليونيكود).

ومن المحتمل، إذا كنت تستخدم utf8_unicode_ci للالحقول، البرامج النصية التي تصل إلى قاعدة البيانات سوف تحتاج إلى تحديث لأذكر الترتيب المطلوب صراحة - الاستفسارات خلاف ذلك باستخدام سلاسل نصية يمكن أن تفشل عند اتصالك يستخدم الترتيب الافتراضي

والنتيجة هي أن عند تحويل النظام القائم مهما كان حجمها إلى Unicode / UTF8، قد ينتهي بك الأمر أن يضطر إلى استخدام utf8_general_ci بسبب الطريقة التي يعالج الخلية الافتراضية.

لقضية أبرزها جوس، أود أن أقترح بشدة باستخدام إما utf8_unicode_cs (القضية الحساسة، ومطابقة صارم، وطلب بشكل صحيح بالنسبة للجزء الأكبر) بدلا من utf8_bin (مطابقة الدقيق للكلمة، ترتيب غير صحيح).

وإذا كان المقصود الحقل المراد تفتيشه، في مقابل مطابقة للمستخدم، ثم استخدام utf8_general_ci أو utf8_unicode_ci. كلاهما حساس لحالة الأحرف، واحد سوف تطابق losely ( 'ß "تساوي الصورة، وليس إلى" SS "). هناك أيضا لغة إصدارات معينة، مثل utf8_german_ci حيث مطابقة يخسر هو أكثر ملاءمة للغة محددة.

[تحرير - بعد ما يقرب من 6 سنوات]

وأنا لم يعد يوصي "UTF8" مجموعة الأحرف في الخلية، وبدلا من ذلك يوصي "utf8mb4" مجموعة الأحرف. أنها تطابق تماما تقريبا، ولكن يسمح للقليلا (الكثير) المزيد من الشخصيات يونيكود.

واقعيا، الخلية يجب أن تحديث "UTF8" مجموعة الأحرف والنسخ منها لتتناسب مع "UTF8" مواصفات، ولكن بدلا من ذلك، شخصية منفصلة تحدد والنسخ منها حتى لا تؤثر على تسمية لتخزين تلك بالفعل استخدام مواردها ناقصة "UTF8 "مجموعة الأحرف.

ولقد وجدت هذه المخططات الترتيب مفيدة. http://collation-charts.org/mysql60/ . أنا لست متأكدا من هو utf8_general_ci المستخدمة بالرغم من ذلك.

وعلى سبيل المثال هنا هو الرسم البياني لutf8_swedish_ci. فإنه يدل على الأحرف التي تفسر على النحو نفسه. http://collation-charts.org/mysql60/mysql604.utf8_swedish_ci.html

في ملف تحميل قاعدة البيانات الخاصة بك، قم بإضافة السطر التالي قبل أي السطر:

SET NAMES utf8;

ويجب ان تحل مشكلتك.

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