web-dev-qa-db-ja.com

MySQLにutf-8エンコーディングを「変換せずに」使用するように指示する

かなりユニークな状況で、私のチームは、データがlatin1としてエンコードされていると考えているデータベースにUTF-8バイトが含まれるようになりました。

少なくとも、私はこれが現在の状況であることを85%確信しています。

たとえば、 右側の単一引用符エンコーディングの概念がなかったプログラミング言語(Ruby 1.8) によってデータベースに渡され、データを未加工のバイト( 0xE2 0x80 0x99)。このデータは、私の知る限り(確認方法は?)、実際のバイトとして格納されていました。したがって、よりインテリジェントなプログラミング言語(Ruby 1.9)でデータが読み取られると、データベースは次のようにわかりやすく表示します "Oh!0xE2 is 'â'、0x80 is '€'、0x99 is '™'" =、「Mike's」の代わりに、「Mike’s」で終わります。これは、その値を選択するときにmysqlプロンプトで取得するものでもあります。

したがって、本質的に、データベースに保存されている一連のutf-8エンコードデータがあり、データはlatin1としてエンコードされていると見なされます。

これは、どういうわけかデータベースに「いいえ、あなたが何を考えていても、これは実際にはutf-8です」と伝えさせます。 CONVERT TOは適切なツールのようには見えません。その場合、永続的な「マイク」が残ることになります。


失敗/無作法な試み#1

私はこれに気づきました:

> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+-------------------+
| Variable_name            | Value             |
+--------------------------+-------------------+
| character_set_client     | utf8              |
| character_set_connection | utf8              |
| character_set_database   | utf8              |
| character_set_filesystem | binary            |
| character_set_results    | utf8              |
| character_set_server     | latin1            |
| character_set_system     | utf8              |
| collation_connection     | utf8_general_ci   |
| collation_database       | utf8_unicode_ci   |
| collation_server         | latin1_swedish_ci |
+--------------------------+-------------------+

そして、character_set_resultslatin1に変更すると、バイトが変換されず、utf8 OSでデータが適切に表示されると考えられます。

案の定、SET character_set_results=latin1;ではなく’になります。涼しい!

それで、これを~/.my.cnfに追加しました(これは、唯一のmy.cnfです。確認しました):

[mysqld]
...
character-set-results=latin1

mySQLプロンプトに戻ってcharacter_set_%変数を確認しても、まだutf8です。

はい、mysqldがデーモンであることがわかりました。つまり、これを有効にするには、おそらくmysqlプロセス全体を再起動する必要があります。しかし、このマシンにMySQLをインストールした人は、brewの代わりにdmgを使用しました(私ではありませんでした)。MySQLの設定ペインでは、MySQLが実行されていないことが明らかに表示されています。ホール、私は実際のDBAに確認して、これがどれほどばかげているか、またはそれを行うためのより良い、よりクリーンな方法があるかどうかを確認したいと思います。

3
chadoh

CONVERT TOを使用してテーブル全体を切り替えるのは、いくつかの理由から悪いニュースです。 mysqlパフォーマンスブログで (概要:CONVERT TOtextを変更する可能性がありますフィールドをmediumtextに入力します)。

しかし、my.cnfの微調整でハッキングするよりも、実際にデータをutf8に変換する方が良いようです。

そのためには、

ALTER TABLE `t1`
MODIFY COLUMN `c1` text CHARACTER SET binary,
MODIFY COLUMN `c2` varchar(255) CHARACTER SET binary;
ALTER TABLE `t1`
DEFAULT CHARSET=utf8,
MODIFY COLUMN `c1` text CHARACTER SET utf8,
MODIFY COLUMN `c2` varchar(255) CHARACTER SET utf8;

データベース内のすべてのテーブルとその関連列。

機能:binaryエンコーディングに変更すると、MySQLは同じバイトを維持しますが、その意味は無視されます。次に、utf8に切り替えても、バイトは同じままです。成功!

この変換により、これらのフィールドのFULLTEXTインデックスがすべて破壊されます(binaryエンコーディングはFULLTEXTインデックスをサポートしていません)。

私は これを自動化するbashスクリプト と書きました。 FULLTEXTインデックスの問題は処理されませんが、出発点としては適しています。

1
chadoh

解決策はまったく同じではありませんが、 この質問 は、最初に同様の問題の方向性を見つけた場所であり、そこにある概念は、あなたが行きたいところへと連れて行ってくれるはずです。 MySQLはBINARY文字セットを持ち、すべての外見からそれを変換することにより、MySQLが実際に行っていることを実現し、「役に立たない」ことを防ぐことができます。

Character_set_client = utf8のテストケース:

mysql> select CONVERT(CONVERT(CONVERT('Mike’s' USING latin1) USING binary) USING utf8);
+--------------------------------------------------------------------------------+
| CONVERT(CONVERT(CONVERT('Mike’s' USING latin1) USING binary) USING utf8)     |
+--------------------------------------------------------------------------------+
| Mike’s                                                                         |
+--------------------------------------------------------------------------------+
1 row in set (0.00 sec)

そのロジックを使用して、MySQLがutf8であると考える新しい列にデータを入力できます。

4