MySQL 5.5 में utf8mb4 को आसानी से utf8 टेबल में कैसे बदलें


71

मेरे पास एक डेटाबेस है जिसे अब 4 बाइट पात्रों (चीनी) का समर्थन करने की आवश्यकता है। सौभाग्य से मेरे पास पहले से ही उत्पादन में MySQL 5.5 है।

इसलिए मैं बस सभी कोलाज बनाना चाहूँगा जो कि utf8mb4_bin को utf8_bin है।

मेरा मानना ​​है कि इस परिवर्तन के साथ कुछ अधिक संग्रहण के साथ कोई प्रदर्शन हानि / लाभ नहीं है।

जवाबों:


93

मेरे गाइड से MySQL डेटाबेस में पूर्ण यूनिकोड का समर्थन कैसे करें , यहां वे प्रश्न हैं जिन्हें आप डेटाबेस, तालिका, या स्तंभ के चारसेट और कोलाज को अपडेट करने के लिए चला सकते हैं:

प्रत्येक डेटाबेस के लिए:

ALTER DATABASE
    database_name
    CHARACTER SET = utf8mb4
    COLLATE = utf8mb4_unicode_ci;

प्रत्येक तालिका के लिए:

ALTER TABLE
    table_name
    CONVERT TO CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;

प्रत्येक स्तंभ के लिए:

ALTER TABLE
    table_name
    CHANGE column_name column_name
    VARCHAR(191)
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;

(इसे नेत्रहीन कॉपी-पेस्ट न करें! सटीक कथन कॉलम प्रकार, अधिकतम लंबाई और अन्य गुणों पर निर्भर करता है। उपरोक्त पंक्ति एक VARCHARकॉलम के लिए केवल एक उदाहरण है ।)

हालांकि, ध्यान रखें कि आप पूरी तरह से से रूपांतरण को स्वचालित नहीं कर सकते utf8करने के लिए utf8mb4। जैसा कि उपर्युक्त मार्गदर्शिका के चरण 4 में वर्णित है , आपको कॉलम और इंडेक्स कुंजियों की अधिकतम लंबाई की जांच करने की आवश्यकता होगी, क्योंकि आपके द्वारा निर्दिष्ट संख्या का एक अलग अर्थ होता utf8mb4है जब इसका उपयोग किया जाता है utf8

MySQL 5.5 संदर्भ मैनुअल की धारा 10.1.11 में इस पर कुछ और जानकारी है।


31

मेरे पास एक समाधान है जो कुछ कमांड चलाकर डेटाबेस और तालिकाओं को बदल देगा। यह भी प्रकार के सभी स्तंभों धर्मान्तरित varchar, text, tinytext, mediumtext, longtext, char। कुछ टूटने की स्थिति में आपको अपने डेटाबेस का बैकअप भी लेना चाहिए ।

निम्नलिखित कोड को एक फ़ाइल में कॉपी करें जिसे इसे preAlterTables.sql कहा जाता है:

use information_schema;
SELECT concat("ALTER DATABASE `",table_schema,"` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;") as _sql 
FROM `TABLES` where table_schema like "yourDbName" group by table_schema;
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name,"` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") as _sql  
FROM `TABLES` where table_schema like "yourDbName" group by table_schema, table_name;
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name, "` CHANGE `",column_name,"` `",column_name,"` ",data_type,"(",character_maximum_length,") CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",IF(is_nullable="YES"," NULL"," NOT NULL"),";") as _sql 
FROM `COLUMNS` where table_schema like "yourDbName" and data_type in ('varchar','char');
SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name, "` CHANGE `",column_name,"` `",column_name,"` ",data_type," CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci",IF(is_nullable="YES"," NULL"," NOT NULL"),";") as _sql 
FROM `COLUMNS` where table_schema like "yourDbName" and data_type in ('text','tinytext','mediumtext','longtext');

"YourDbName" की सभी घटनाओं को उस डेटाबेस से बदलें, जिसे आप कनवर्ट करना चाहते हैं। तो भागो:

mysql -uroot < preAlterTables.sql | egrep '^ALTER' > alterTables.sql

यह एक नई फ़ाइल को बदल देगा ।Tables.sql, डेटाबेस को बदलने के लिए आवश्यक सभी प्रश्नों के साथ। रूपांतरण शुरू करने के लिए निम्नलिखित कमांड चलाएँ:

mysql -uroot < alterTables.sql

आप कई डेटाबेस के माध्यम से चलाने के लिए इसे अनुकूलित कर सकते हैं, table_schema के लिए स्थिति बदलकर। उदाहरण के लिए table_schema like "wiki_%"उपसर्ग नाम के साथ सभी डेटाबेसों को परिवर्तित करेगा wiki_। सभी डेटाबेस को बदलने के लिए शर्त को बदलें table_type!='SYSTEM VIEW'

एक मुद्दा जो उत्पन्न हो सकता है। मेरे mysql कुंजियों में कुछ varchar (255) कॉलम थे। यह एक त्रुटि का कारण बनता है:

ERROR 1071 (42000) at line 2229: Specified key was too long; max key length is 767 bytes

यदि ऐसा होता है, तो आप वर्कर को छोटा करने के लिए बदल सकते हैं, जैसे कि varchar (150), और कमांड को फिर से चलाएँ।

कृपया ध्यान दें : यह उत्तर प्रश्न में पूछे गए के utf8mb4_unicode_ciबजाय डेटाबेस को रूपांतरित करता है utf8mb4_bin। लेकिन आप बस इसे बदल सकते हैं।


महान स्क्रिप्टिंग, बस कुछ नोट्स; वर्तमान MiariaDb इंस्टॉल को पासवर्ड देने की आवश्यकता होती है, इसलिए mysql -uroot -pThatrootPassWord < alterTables.sqlकाम करता है। और जैसा कि आपने पहले ही नोट किया था, utf8mb4_bin क्या है, दूसरों के बीच में, नेक्लाउड अनुशंसा करता है।
जूलियस

लेकिन utf8mb4_0900_ai_ci अभी डिफ़ॉल्ट है, देखें monolune.com/what-is-the-utf8mb4_0900_ai_ci-collation
Julius

मुझे "SET Foreign_key_checks = 0;" का उपयोग करना था, फिर परिवर्तनों को लागू करना था, फिर "SET Foreign_key_checks = 1;"।
dfrankow

आपको धन्यवाद। यह Redmin में सभी utf8mb4 में बदलने के लिए समाधान था।
लुसियानो फैंटुजी

5

मैंने निम्नलिखित शेल स्क्रिप्ट का उपयोग किया। यह डेटाबेस के नाम को एक पैरामीटर के रूप में लेता है और सभी तालिकाओं को दूसरे चार्टसेट और कॉलेशन (किसी अन्य पैरामीटर द्वारा दिए गए या स्क्रिप्ट में परिभाषित डिफ़ॉल्ट मान) में परिवर्तित करता है।

#!/bin/bash

# mycollate.sh <database> [<charset> <collation>]
# changes MySQL/MariaDB charset and collation for one database - all tables and
# all columns in all tables

DB="$1"
CHARSET="$2"
COLL="$3"

[ -n "$DB" ] || exit 1
[ -n "$CHARSET" ] || CHARSET="utf8mb4"
[ -n "$COLL" ] || COLL="utf8mb4_general_ci"

echo $DB
echo "ALTER DATABASE \`$DB\` CHARACTER SET $CHARSET COLLATE $COLL;" | mysql

echo "USE \`$DB\`; SHOW TABLES;" | mysql -s | (
    while read TABLE; do
        echo $DB.$TABLE
        echo "ALTER TABLE \`$TABLE\` CONVERT TO CHARACTER SET $CHARSET COLLATE $COLL;" | mysql $DB
    done
)

3

मैं सभी तालिकाओं के माध्यम से चलने के लिए Information_schema (TABLES और COLUMNS) का उपयोग करने के लिए एक स्क्रिप्ट (Perl, या जो कुछ भी) लिखूंगा और प्रत्येक CHAR / VARCHAR / TAT फ़ील्ड पर MODIFY COLUMN करूँगा। मैं प्रत्येक तालिका के लिए सभी MODIFYs को एक ही अक्षर में एकत्रित करूंगा; यह अधिक कुशल होगा।

मुझे लगता है (लेकिन मुझे यकीन नहीं है) कि रहान का सुझाव केवल तालिका के लिए डिफ़ॉल्ट को बदलता है ।


3

इस स्थिति में भाग गया; यहाँ मैं अपने डेटाबेस को बदलने के लिए उपयोग किया है:

  1. सबसे पहले, आपको my.cnfडिफ़ॉल्ट डेटाबेस कनेक्शन (अनुप्रयोगों और MYSQL के बीच) utf8mb4_unicode_ci के अनुरूप बनाने के लिए संपादित करना होगा। इस तरह के पात्रों के बिना इमोजीज़ और आपके ऐप्स द्वारा समान सबमिट किए जाने से यह सही बाइट्स / एन्कोडिंग में आपके टेबल पर नहीं आएगा (जब तक कि आपके एप्लिकेशन का DB CNN परम एक utf8mb4 कनेक्शन निर्दिष्ट नहीं करता है)।

    यहां दिए गए निर्देश ।

  2. निम्न SQL निष्पादित करें (अलग-अलग स्तंभों को बदलने के लिए तैयार SQL प्राप्त करने की आवश्यकता नहीं है, ALTER TABLEकथन ऐसा करेंगे)।

    इससे पहले कि आप नीचे दिए गए कोड को अपने वास्तविक DB नाम के साथ "DbName" बदलें।

    USE information_schema;
    
    SELECT concat("ALTER DATABASE `",table_schema,
                  "` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;") as _sql
      FROM `TABLES`
     WHERE table_schema like "DbName"
     GROUP BY table_schema;
    
    SELECT concat("ALTER TABLE `",table_schema,"`.`",table_name,
                  "` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;") as _sql
      FROM `TABLES`
     WHERE table_schema like "DbName"
     GROUP BY table_schema, table_name;
  3. डॉट एसक्यूएल फ़ाइल में एसक्यूएल के ऊपर आउटपुट को इकट्ठा करें और सहेजें और इसे निष्पादित करें।

  4. यदि आपको #1071 - Specified key was too long; max key length is 1000 bytes.समस्याग्रस्त तालिका नाम के साथ एक त्रुटि मिलती है , तो इसका मतलब है कि उस तालिका के कुछ स्तंभों पर सूचकांक कुंजी (जिसे एमबी 4 चार्टिंग में परिवर्तित किया जाना चाहिए) बहुत बड़ा होगा, ताकि वर्चर कॉलम <= 250 होना चाहिए ताकि इसका इंडेक्स कुंजी अधिकतम 1000 बाइट्स होगी। उन स्तंभों की जांच करें जिन पर आपके पास अनुक्रमित हैं और यदि उनमें से एक varchar> 250 (सबसे अधिक संभावना 255) है

    • चरण 1: उस कॉलम में डेटा की जाँच करें ताकि यह सुनिश्चित हो सके कि उस कॉलम में अधिकतम स्ट्रिंग का आकार <= 250 है।

      उदाहरण क्वेरी:

      select `id`,`username`, `email`,
             length(`username`) as l1,
             char_length(`username`) as l2,
             length(`email`) as l3,
             char_length(`email`) as l4
        from jos_users
       order by l4 Desc;
    • चरण 2: यदि अनुक्रमित स्तंभ डेटा की अधिकतम वर्णक्रांति <= 250 है तो कर्नल की लंबाई को 250 में बदलें। यदि यह संभव नहीं है, तो उस स्तंभ पर अनुक्रमणिका निकालें

    • चरण 3: फिर उस तालिका के लिए परिवर्तन तालिका क्वेरी को फिर से चलाएँ और तालिका को अब सफलतापूर्वक utf8mb4 में परिवर्तित किया जाना चाहिए।

चीयर्स!


191 से अधिक वर्णों पर लंबे VARCHAR के लिए सूचकांक का उपयोग करने का एक तरीका है। आपके पास DBA / SUPER USER विशेषाधिकार होना चाहिए: डेटाबेस पैरामीटर सेट करना: innodb_large_prefix: ON; innodb_file_format: बाराकुडा; innodb_file_format_max: बाराकुडा;
चिंटू ल्हेन

2

मैंने यह गाइड लिखा है: http://hanoian.com/content/index.php/24-automate-the-converting-a-mysql-database-character-set-to-utf8mb4

अपने काम से, मैंने देखा कि डेटाबेस और तालिकाएँ पर्याप्त नहीं हैं। मुझे प्रत्येक तालिका में जाना था और प्रत्येक पाठ / माध्यम / varchar कॉलम को भी बदलना था।

सौभाग्य से मैं MySQL डेटाबेस के मेटाडेटा का पता लगाने के लिए एक स्क्रिप्ट लिखने में सक्षम था, इसलिए यह तालिकाओं और स्तंभों के माध्यम से लूप कर सकता है और उन्हें स्वचालित रूप से बदल सकता है।

MySQL 5.6 के लिए लंबा सूचकांक:

ऐसा करने के लिए आपके पास DBA / SUPER USER विशेषाधिकार होना चाहिए: डेटाबेस पैरामीटर सेट करना एक बात है:

innodb_large_prefix: चालू
innodb_file_format: बाराकुडा 
innodb_file_format_max: बाराकुडा

इस प्रश्न के उत्तर में, उन मापदंडों को ऊपर सेट करने का निर्देश है: https://stackoverflow.com/questions/35847015/mysql-change-innodb-large-prefix

बेशक, मेरे लेख में, ऐसा करने के निर्देश भी हैं।

MySQL संस्करण 5.7 या नए के लिए , innodb_large_prefix डिफ़ॉल्ट रूप से चालू है, और innodb_file_format डिफ़ॉल्ट रूप से बाराकुडा भी है।


2

जिन लोगों को यह समस्या हो सकती है, उनके लिए सबसे अच्छा उपाय यह है कि पहले कॉलम को एक बाइनरी प्रकार में बदल दिया जाए, इस तालिका के अनुसार:

  1. चार => द्विवर्षीय
  2. TEXT => BLOB
  3. TINYTEXT => TINYBLOB
  4. MEDIUMTEXT => MEDIUMBLOB
  5. LONGTEXT => LONGBLOB
  6. वर्कर => वार्बिनरी

और इसके बाद कॉलम को अपने पूर्व प्रकार में और अपने इच्छित चार्ट के साथ संशोधित करें।

उदाहरण के लिए .:

ALTER TABLE [TABLE_SCHEMA].[TABLE_NAME] MODIFY [COLUMN_NAME] LONGBLOB;
ALTER TABLE [TABLE_SCHEMA].[TABLE_NAME] MODIFY [COLUMN_NAME] VARCHAR(140) CHARACTER SET utf8mb4;

मैंने कई लेट 1 टेबलों में कोशिश की और इसने सभी डिक्टिटिक्स को रखा।

आप ऐसा करने वाले सभी कॉलम के लिए यह क्वेरी निकाल सकते हैं:

SELECT
CONCAT('ALTER TABLE ', TABLE_SCHEMA,'.', TABLE_NAME,' MODIFY ', COLUMN_NAME,' VARBINARY;'),
CONCAT('ALTER TABLE ', TABLE_SCHEMA,'.', TABLE_NAME,' MODIFY ', COLUMN_NAME,' ', COLUMN_TYPE,' CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;')
FROM information_schema.columns
WHERE TABLE_SCHEMA IN ('[TABLE_SCHEMA]')
AND COLUMN_TYPE LIKE 'varchar%'
AND (COLLATION_NAME IS NOT NULL AND COLLATION_NAME NOT LIKE 'utf%');

0

मैंने एक स्क्रिप्ट बनाई है जो कम या ज्यादा स्वचालित रूप से करती है:

<?php
/**
 * Requires php >= 5.5
 * 
 * Use this script to convert utf-8 data in utf-8 mysql tables stored via latin1 connection
 * This is a PHP port from: https://gist.github.com/njvack/6113127
 *
 * BACKUP YOUR DATABASE BEFORE YOU RUN THIS SCRIPT!
 *
 * Once the script ran over your databases, change your database connection charset to utf8:
 *
 * $dsn = 'mysql:host=localhost;port=3306;charset=utf8';
 * 
 * DON'T RUN THIS SCRIPT MORE THAN ONCE!
 *
 * @author hollodotme
 *
 * @author derclops since 2019-07-01
 *
 *         I have taken the liberty to adapt this script to also do the following:
 *
 *         - convert the database to utf8mb4
 *         - convert all tables to utf8mb4
 *         - actually then also convert the data to utf8mb4
 *
 */

header('Content-Type: text/plain; charset=utf-8');

$dsn      = 'mysql:host=localhost;port=3306;charset=utf8';
$user     = 'root';
$password = 'root';
$options  = [
    \PDO::ATTR_CURSOR                   => \PDO::CURSOR_FWDONLY,
    \PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
    \PDO::MYSQL_ATTR_INIT_COMMAND       => "SET CHARACTER SET latin1",
];


$dbManager = new \PDO( $dsn, $user, $password, $options );

$databasesToConvert = [ 'database1',/** database3, ... */ ];
$typesToConvert     = [ 'char', 'varchar', 'tinytext', 'mediumtext', 'text', 'longtext' ];

foreach ( $databasesToConvert as $database )
{
    echo $database, ":\n";
    echo str_repeat( '=', strlen( $database ) + 1 ), "\n";

    $dbManager->exec( "USE `{$database}`" );

    echo "converting database to correct locale too ... \n";

    $dbManager->exec("ALTER DATABASE `{$database}` CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci");


    $tablesStatement = $dbManager->query( "SHOW TABLES" );
    while ( ($table = $tablesStatement->fetchColumn()) )
    {
        echo "Table: {$table}:\n";
        echo str_repeat( '-', strlen( $table ) + 8 ), "\n";

        $columnsToConvert = [ ];

        $columsStatement = $dbManager->query( "DESCRIBE `{$table}`" );

        while ( ($tableInfo = $columsStatement->fetch( \PDO::FETCH_ASSOC )) )
        {
            $column = $tableInfo['Field'];
            echo ' * ' . $column . ': ' . $tableInfo['Type'];

            $type = preg_replace( "#\(\d+\)#", '', $tableInfo['Type'] );

            if ( in_array( $type, $typesToConvert ) )
            {
                echo " => must be converted\n";

                $columnsToConvert[] = $column;
            }
            else
            {
                echo " => not relevant\n";
            }
        }


        //convert table also!!!
        $convert = "ALTER TABLE `{$table}` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci";

        echo "\n", $convert, "\n";
        $dbManager->exec( $convert );
        $databaseErrors = $dbManager->errorInfo();
        if( !empty($databaseErrors[1]) ){
            echo "\n !!!!!!!!!!!!!!!!! ERROR OCCURED ".print_r($databaseErrors, true)." \n";
            exit;
        }


        if ( !empty($columnsToConvert) )
        {
            $converts = array_map(
                function ( $column )
                {
                    //return "`{$column}` = IFNULL(CONVERT(CAST(CONVERT(`{$column}` USING latin1) AS binary) USING utf8mb4),`{$column}`)";
                    return "`{$column}` = CONVERT(BINARY(CONVERT(`{$column}` USING latin1)) USING utf8mb4)";
                },
                $columnsToConvert
            );

            $query = "UPDATE IGNORE `{$table}` SET " . join( ', ', $converts );

            //alternative
            // UPDATE feedback SET reply = CONVERT(BINARY(CONVERT(reply USING latin1)) USING utf8mb4) WHERE feedback_id = 15015;


            echo "\n", $query, "\n";


            $dbManager->exec( $query );

            $databaseErrors = $dbManager->errorInfo();
            if( !empty($databaseErrors[1]) ){
                echo "\n !!!!!!!!!!!!!!!!! ERROR OCCURED ".print_r($databaseErrors, true)." \n";
                exit;
            }
        }

        echo "\n--\n";
    }

    echo "\n";
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.