|
Защо базата има нужда от енкодинг?
Не може ли просто да съхранява байтове и да ни ги подава непроменени, когато ни потрябват? Би могло. Но тя има амбицията, освен съхраняването на данните, да ни предостави и функции, с които да я караме да ни връща по-сложни резултати. Сортиране, групиране, преобразуване на малки в главни букви, търсене с маска, дати, всякакви неща... За правилната работа на част от тези функции базата трябва да знае дали байтовете, които сме записали в нея, за нас имат смисъл на стринг, или пък са число, дата или друго. Примерно за да ни подаде 5-тата буква от даден текст, тя трябва да знае с колко байта се записва 1 буква. Как ще получи от малко "щ" главно "Щ", ако не знае с кои байтове се изписва то? Поради разликите в разположението на буквите в различните кодови таблици, тази задача (капитализацията) се решава различно. За да може да служи еднакво добре и на шведи, и на българи, базата има не едно, а цяла серия от различни поведения: AllCaps_кирилица(), AllCaps_шведица(), AllCaps_патагоница... И от нас очаква да й кажем кое от тях искаме да ползва, когато напишем AllCaps(). Това ние правим като задаваме енкодинги. Така възприемам ролята им - като "параметър на стринговите функции". Кога? Кога базата прекодира нашите данни и как ги съхранява вътрешно? Указвайки енкодинга на поле от някоя таблица, ние сигнализираме кои конкретни версии на стринговите функции важат за това поле. От този момент нататък базата започва да ПРЕКОДИРА байтовете, които й вкарваме, преди да си ги запише в полето. Тя върши тази промяна ако:
Сега малко по-подробно: В MySQL 4.1+, освен енкодинга на полетата, ние трябва да укажем и енкодинг на връзката ни с базата. Ако кажем, че връзката е "utf8", това означава, че нещата, които й пращаме, са смислени символи в тази кодова таблица. Това ни задължава от този момент нататък да й подаваме само поредици от байтове, които са валидни в utf8. Опитаме ли да подадем "грешен" байт, ще получим съобщение, че "полето е прекалено късо за тези данни" или нещо подобно, но истинското съобщение би трябвало да гласи "сега що ме лъжеш?". Ако пък наистина й подаваме utf8 данни, тя ще ги запише 1:1, стига да са били предназначени за поле, чийто енкодинг също е utf8. Ако нашите utf8 данни обаче трябва да попаднат в колонка с 1251, базата ще опита да ги конвертира, преди да ги запише. Грубо казано тя гледа графично какво "ченгелче" е изобразено с този utf8-байт и търси с кой байт същото ченгелче участва в 1251. Ако го намери - записва намерения байт. Ако не - казва, че "част от данните ще бъдат изгубени" и записва нещо си, което после виждаме като "???". Така че базата НЕ ПРЕКОДИРА данни само в случаите, или когато колоната е била в някой от binary-типовете (това е тяхното предназначение - имат табелка "не пипай, не прекодирай!"), или когато двата енкодинга са съвпадали. Прекодирането се случва бързо и почти неусетно. При тази технология, в една MySQL 5 таблица имаме колони, на всяка от които пише в какъв енкодинг са данните в нея и тази информация й служи за преценката:
Възможността да има различни енкодинги за всяка таблица и дори за всяко нейно поле е особеност на MySQL 4.1+. Това отсъства в предните версии на тая СУБД, няма го в Оракъл, Access, а вероятно и другаде липсва. Доколкото ми е известно същото важи и за енкодинга на връзката. При останалите бази предварително избираме какви данни ще подаваме, и заковаваме завинаги енгодинга на връзката да е същия, като оня, който сме указали за цялата база. Това я спасява от нуждата да прекодира постъпващите данни. Подозирам, че причината е в скоростта на прекодирането - по някое време в MySQL са разработили скорострелен начин да го вършат и чак тогава е станало разумно да ни "отвържат ръцете". Но опреледено е удобно да можеш да смениш енкодинга на сайта си, без да се грижиш да променяш и базата - сменяш само 1 дума за връзката с нея и си готов. Лично аз се възползвах от това положение в сайт, който получава част от данните си в 1251 (през браузер), а друга част идват в utf8 (през чужд сървис). Със старата версия на базата ми се налагаше да прекодирам всяко стрингче, преди да й го подам, което обезобрази сорса, а сега само времено в движение сменям енкодинга на връзката и после го връщам на 1251. Всичко, казано по процеса на вкарване да данни в MySQL5, важи също и за изваждането им. Клиента (да кажем сайта), обявявайки енкодинга на връзката, също така принуждава базата да му конвертира обратно данните, преди да му ги даде. Това прави двете системи напълно независими откъм енкодинг. Клиента вече може да си позволи дори да не знае какви енкодинги имат полетата в таблиците. Той й казва "давам ти 1251", айде сега ми го върни в "латин1" и изобщо каквото си пожелае, и тя изпълнява. Обичайните клиенти на нашата база са:
За всеки от тези клиенти е важно да можем да сетваме правилно енкодинг на връзката (и да не забравяме да го правим). За мен най-трудно се оказва дирижирането на енкодинга на създавания от нея dump. Ако имаме достъп до базата през конзола, там можем да го зададем в явен вид в командата. Ако го правим през phpMyAdmin мисля, че също е възможно, но все още не съм успяла да го направя. Тук накратко може да се каже нещичко и за понятието "Колация". Тя не е нищо повече от "азбучен ред". Свързана е с кодовата таблица - вътре в един енкодинг може да има повече от една колации. Например в латин1 има буква, която се изобразява като "О" с две точки отгоре. Тя е назад в таблицата, след "Z", но в някои езици се намира на различни места в азбучния ред. Примерно при шведите трябва да е веднага след обикновеното "O", а при финландците се редяла по-назад. Колацията показва коя версия на функцията Order() да се ползва. За щастие, всички езици, ползващи кирилица, имат еднакви азбучни подредби и проблеми с колации няма да имаме често (освен евентуално при македонците - не знам те къде си подреждат буквата j). Така или иначе смяната на колацията не причинява прекодиране или каквото и да е друго допълнително действие вътре в базата.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||









