سؤال

هل يمكنني استخدام varchar(36) أو هل هناك طرق أفضل للقيام بذلك ؟

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

المحلول

سألني

وبلدي DBA عندما سألت عن أفضل طريقة لتخزين المعرفات الفريدة العمومية للكائنات لي لماذا أنا في حاجة لتخزين 16 بايت عند يمكنني أن أفعل نفس الشيء في 4 بايت مع عدد صحيح. منذ أن وضع هذا التحدي هناك بالنسبة لي أعتقد أنه كان الآن هو الوقت المناسب لأذكر ذلك. أن يقال ...

ويمكنك تخزين ثنائي GUID مثل CHAR (16) إذا كنت ترغب في تحقيق أقصى استفادة الأمثل من مساحة التخزين.

نصائح أخرى

وأود أن تخزينه كما شار (36).

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

DELIMITER $$

CREATE FUNCTION `GuidToBinary`(
    $Data VARCHAR(36)
) RETURNS binary(16)
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result BINARY(16) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Data = REPLACE($Data,'-','');
        SET $Result =
            CONCAT( UNHEX(SUBSTRING($Data,7,2)), UNHEX(SUBSTRING($Data,5,2)),
                    UNHEX(SUBSTRING($Data,3,2)), UNHEX(SUBSTRING($Data,1,2)),
                    UNHEX(SUBSTRING($Data,11,2)),UNHEX(SUBSTRING($Data,9,2)),
                    UNHEX(SUBSTRING($Data,15,2)),UNHEX(SUBSTRING($Data,13,2)),
                    UNHEX(SUBSTRING($Data,17,16)));
    END IF;
    RETURN $Result;
END

$$

CREATE FUNCTION `ToGuid`(
    $Data BINARY(16)
) RETURNS char(36) CHARSET utf8
DETERMINISTIC
NO SQL
BEGIN
    DECLARE $Result CHAR(36) DEFAULT NULL;
    IF $Data IS NOT NULL THEN
        SET $Result =
            CONCAT(
                HEX(SUBSTRING($Data,4,1)), HEX(SUBSTRING($Data,3,1)),
                HEX(SUBSTRING($Data,2,1)), HEX(SUBSTRING($Data,1,1)), '-', 
                HEX(SUBSTRING($Data,6,1)), HEX(SUBSTRING($Data,5,1)), '-',
                HEX(SUBSTRING($Data,8,1)), HEX(SUBSTRING($Data,7,1)), '-',
                HEX(SUBSTRING($Data,9,2)), '-', HEX(SUBSTRING($Data,11,6)));
    END IF;
    RETURN $Result;
END
$$

وCHAR(16) هو في الواقع BINARY(16)، اختر النكهة المفضلة

لمتابعة قانون أفضل، واتخاذ سبيل المثال نظرا لGUID بأمر الرقم أدناه. (استخدام أحرف غير قانونية لأغراض التوضيح - كل مكان طابع فريد.) وتكون مهام تحويل ترتيب البايت لتحقيق أمر بت لمتفوقة تجميع مؤشر. يظهر ارشد إعادة ترتيب أدناه المثال.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
78563412-BC9A-FGDE-HIJK-LMNOPQRSTUVW

وشرطات إزالة:

123456789ABCDEFGHIJKLMNOPQRSTUVW
78563412BC9AFGDEHIJKLMNOPQRSTUVW

وشار (36) من شأنه أن يكون خيارا جيدا. أيضا وظيفة () UUID الخلية يمكن استخدام والتي ترجع شكل النص 36-حرف (عرافة مع الواصلات) والتي يمكن استخدامها لاسترجاع هذه المعرفات من ديسيبل.

و"أفضل" يعتمد على ما كنت الأمثل ل.

وكم كنت تهتم حجم التخزين / الأداء مقابل سهولة التنمية؟ الأهم من ذلك - أنت توليد ما يكفي من المعرفات الفريدة العمومية، أو جلب لهم في كثير من الأحيان بما فيه الكفاية، وأنه يهم

إذا كان الجواب "لا"، char(36) أكثر من جيدة بما فيه الكفاية، وأنه يجعل تخزين / جلب المعرفات الفريدة العمومية ميتا بسيطة. خلاف ذلك، binary(16) هو معقول، ولكن عليك أن تضغط على MySQL و / أو لغة البرمجة التي تختارها لتحويل ذهابا وإيابا من تمثيل سلسلة المعتاد.

وثنائي (16) سيكون على ما يرام، وأفضل من استخدام VARCHAR (32).

على GuidToBinary الروتينية أرسلت بواسطة KCD أن أنب لحساب بت التخطيط الزمني في سلسلة المعرف الفريد العمومي.إذا كانت السلسلة يمثل الإصدار 1 UUID, مثل تلك التي تم إرجاعها بواسطة uuid() الخلية الروتينية ، ثم الوقت المكونات المضمنة في رسائل 1-ز ، باستثناء D.

12345678-9ABC-DEFG-HIJK-LMNOPQRSTUVW
12345678 = least significant 4 bytes of the timestamp in big endian order
9ABC     = middle 2 timestamp bytes in big endian
D        = 1 to signify a version 1 UUID
EFG      = most significant 12 bits of the timestamp in big endian

عند تحويل الثنائية, أفضل نظام الفهرسة ليكون:EFG9ABC12345678D + بقية.

كنت لا ترغب في مبادلة 12345678 إلى 78563412 لأن endian كبير بالفعل ينتج أفضل ثنائي مؤشر ترتيب بايت.ومع ذلك, كنت لا تريد أهم بايت نقل أمام أقل بايت.ومن ثم المجموعة المالية أولا ، تليها منتصف بت بت أقل.توليد عشرات أو حتى UUIDs مع uuid() على مدى دقيقة و يجب أن نرى كيف أن هذا النظام ينتج رتبة الصحيحة.

select uuid(), 0
union 
select uuid(), sleep(.001)
union 
select uuid(), sleep(.010)
union 
select uuid(), sleep(.100)
union 
select uuid(), sleep(1)
union 
select uuid(), sleep(10)
union
select uuid(), 0;

/* output */
6eec5eb6-9755-11e4-b981-feb7b39d48d6
6eec5f10-9755-11e4-b981-feb7b39d48d6
6eec8ddc-9755-11e4-b981-feb7b39d48d6
6eee30d0-9755-11e4-b981-feb7b39d48d6
6efda038-9755-11e4-b981-feb7b39d48d6
6f9641bf-9755-11e4-b981-feb7b39d48d6
758c3e3e-9755-11e4-b981-feb7b39d48d6 

أول اثنين UUIDs تم إنشاؤها في أقرب وقت.إلا أنها تختلف في آخر 3 يقضم من المربع الأول.هذه هي الأقل أهمية بت الزمني ، وهو ما يعني أننا نريد أن دفعهم إلى اليمين عندما نقوم بتحويل هذا إلى إدراج فهرسة صفيف بايت.عداد مثال آخر معرف هو الأكثر الحالية ، ولكن KCD مبادلة خوارزمية وضعه قبل 3 معرف (3e قبل dc, آخر بايت من القسم الأول).

الترتيب الصحيح الفهرسة ليكون:

1e497556eec5eb6... 
1e497556eec5f10... 
1e497556eec8ddc... 
1e497556eee30d0... 
1e497556efda038... 
1e497556f9641bf... 
1e49755758c3e3e... 

انظر هذه المقالة للحصول على معلومات داعمة: http://mysql.rjweb.org/doc.php/uuid

*** ملاحظة أنه لا تقسيم النسخة عاب من 12 بت عالية الزمني.هذا هو د عاب من المثال الخاص بك.أنا فقط رميها في الجبهة.لذا الثنائية تسلسل ينتهي DEFG9ABC وهلم جرا.وهذا يعني أن كل فهرسة UUIDs تبدأ مع نفس عاب.المادة يفعل الشيء نفسه.

لتلك مجرد عثرة عبر هذه، والآن هناك بديل أفضل بكثير وفقا لبحث أجرته Percona.

ويتكون من إعادة تنظيم قطع UUID للفهرسة الأمثل، ثم تحويلها إلى ثنائي لخفض التخزين.

هنا

وأود أن أقترح استخدام وظائف أدناه منذ تلك التي كتبها @ bigh_29 المذكورة تحول المعرفات الفريدة العمومية في بلدي جديدة (لأسباب لا أفهم). أيضا، وهذه هي أسرع قليلا في الاختبارات فعلت في الجداول بلدي. https://gist.github.com/damienb/159151

DELIMITER |

CREATE FUNCTION uuid_from_bin(b BINARY(16))
RETURNS CHAR(36) DETERMINISTIC
BEGIN
  DECLARE hex CHAR(32);
  SET hex = HEX(b);
  RETURN LOWER(CONCAT(LEFT(hex, 8), '-', MID(hex, 9,4), '-', MID(hex, 13,4), '-', MID(hex, 17,4), '-', RIGHT(hex, 12)));
END
|

CREATE FUNCTION uuid_to_bin(s CHAR(36))
RETURNS BINARY(16) DETERMINISTIC
RETURN UNHEX(CONCAT(LEFT(s, 8), MID(s, 10, 4), MID(s, 15, 4), MID(s, 20, 4), RIGHT(s, 12)))
|

DELIMITER ;

وإذا كان لديك قيمة شار / VARCHAR تنسيق مثل GUID القياسية، يمكنك ببساطة تخزينه كما BINARY (16) باستخدام CAST بسيط (MyString AS BINARY16)، من دون كل هذه التسلسلات محيرة للعقل CONCAT + SUBSTR.

وBINARY (16) الحقول مقارنة / فرز / فهرستها بشكل أسرع بكثير من السلاسل، وأيضا تأخذ مساحة أقل مرتين في قاعدة البيانات

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