MySQL文字データ型charとvarcharの違い

10050 ワード

データ型の差はmysqlに接触して最初から知っていた内容で、最近varcharがmediumtextを自動的に回転したり、blobのストレージ性能が問題になったりして、MySQLの一般的なデータ型の選択を振り返って明確にしなければなりません.
mysqlマニュアルここではよく説明されています.いずれも文字列型フィールドを定義するときによく使用されるタイプですが、格納と取得の方法には異なり、最大長と末尾のスペースが保持されているかどうかにも違いがあります.charタイプは、固定長空間を用いて記憶され、範囲0〜255である.例えばCHAR(30)は30バイトを置くことができ、abcdを保存すると、末尾がスペースで補完され、実際に30 bytesのスペースが占有されます.検索すると末尾スペースが除去されます.
charは、type、ipアドレス、md 5など、常に変化する値を格納したり、長さが相対的に固定された値を格納したりするのが上手で、フラグメントが発生しにくい.その効率についてはここを参照してください.varcharタイプは、0〜65535の範囲の可変長文字列を保存する(ただし、単行最大64 kbの制限を受ける).例えば、abcdはvarchar(30)で格納され、実際には5バイトが使用される.文字列の長さを識別するために追加の1バイトが必要であるため(0〜255は1バイト、255を超えると2バイトが必要である).
varcharは値を格納するのに長短の異なる列であり、ディスク容量を節約するために最も多くのタイプを使用しています.update時にvarchar列を作成する場合、新しいデータが元のデータより大きい場合、データベースがスペースを再開する必要があるため、パフォーマンスに多少の損失がありますが、innodbエンジンではcharよりもクエリー効率が高くなります.これもinnodb公式推薦のタイプです.
保存時の実際の長さがcharまたはvarchar定義の最大長を超えている場合は?
  • SQL厳格モードでは、charまたはvarcharにかかわらず、末尾が切り捨てられる非スペースの場合、挿入に失敗した
  • というエラーが表示されます.
  • SQL非厳格モードでは、charまたはvarcharにかかわらず、末尾が切断される非スペースの場合、warningが提示されますが、
  • に成功します.
  • 末尾がスペースで切断される場合、SQLのモードにかかわらずvarcharは正常に挿入できますが、warningをプロンプトします.charは挿入に成功し、何のヒントもない
  • ここでわざわざSQLの厳格モードに言及したのは、仕事中にもいくつかの穴に遭遇したことがあるので、[MySQLのsql_mode厳格モード注意点]()を参考にしてください.
    公式の表を貼り付けます.
    Value
    CHAR(4)
    Storage Required
    VARCHAR(4)
    Storage Required
    ''
    ' '
    4 bytes
    ''
    1 byte
    'ab'
    'ab '
    4 bytes
    'ab'
    3 bytes
    'abcd'
    'abcd'
    4 bytes
    'abcd'
    5 bytes
    'abcdefgh'
    'abcd'
    4 bytes
    'abcd'
    5 bytes
    また、mysqlフィールドの値比較の場合、デフォルトでは大文字と小文字を区別しません.これは、彼らの校正規則(一般的にutf 8_general_ci)によって決定され、文字で比較されるため、クエリー時の値の末尾のスペースも無視されます.表作成時に列にBINARY(校正文字セットがutf 8_binになる)またはselect * from vc where binary v='ab ';を指定しない限り、バイトで比較されます.つまり、比較時に大文字と小文字を区別します.
    ただし、varcharを使用すると、長さが可変であるため、90バイトで十分な列をvarchar(200)として定義することはできません.メモリを開く際に200バイトで行われるため、filesortやtmp tableジョブが必要な場合に不利な影響を及ぼす可能性があります.
    最後に、create table tc_utf8(c1 int primary key auto_increment, c2 char(30), c3 varchar(N)) charset=utf8;を例に、文字セットがストレージ長に及ぼす影響について検討します.
    文字セットはutf 8であるため、中国語は文字ごとに3バイトを占め、英語は1バイトであるため、Nは最大(65535-1-2-4-303)/3=21812であり、すなわち最大21812個の英語、数字、漢字を格納することができる.このうち65535は単行最大制限であり、マイナス1はNULL識別ビットであり、マイナス2はヘッダの2バイト識別長であり、マイナス303はchar(30)が90バイトを占有し、最後に3で割ったのか、utf 8が最も長いため3バイトで1文字を表すのかである.
    しかし、utf 8の英語文字は1バイトしか表示されず、3バイトを占有していないという人もいますが、ASCII文字を保存している場合はNがもっと大きくなるのではないでしょうか.答えは否定的で、定義表の時mysqlは事前にc 3が英語でまだ中国語であることを知らなかったので、最大で計算するしかありません.mysqlもこのようにして行の最大65535 bytes制限を確保しています.データ行にはascii文字(アルファベット、数字など)が1つ現れるだけで、65535には達しません.データ行は中国語でちょうどいっぱいです.
    もう1つの特殊な状況があります.
    mysql> show variables like "char%";
    +--------------------------+----------------------------+
    | 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                       |
    | character_sets_dir       | /usr/share/mysql/charsets/ |
    +--------------------------+----------------------------+
    8 rows in set (0.12 sec)
    
    mysql> select @@sql_mode;
    +------------------------+
    | @@sql_mode             |
    +------------------------+
    | NO_ENGINE_SUBSTITUTION |
    +------------------------+
    1 rows in set (0.13 sec)
    
    mysql> create table tc_utf8_21812(c1 int primary key auto_increment, c2 char(30), c3 varchar(21812)) charset=utf8;
    Query OK, 0 rows affected (0.10 sec)
    
    mysql> create table tc_utf8_21813(c1 int primary key auto_increment, c2 char(30), c3 varchar(21845)) charset=utf8;
    Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
    
    mysql> create table tc_utf8_21846(c1 int primary key auto_increment, c2 char(30), c3 varchar(21846)) charset=utf8;
    Query OK, 0 rows affected, 1 warnings (0.10 sec)
    
    mysql> show warnings;
    +-------+------+---------------------------------------------+
    | Level | Code | Message                                     |
    +-------+------+---------------------------------------------+
    | Note  | 1246 | Converting column 'c3' from VARCHAR to TEXT |
    +-------+------+---------------------------------------------+
    1 rows in set (0.14 sec)
    

    すなわち、非厳格モードでは、N=21813>21812のため、Row size too largeエラーが報告される.ただしN=21846>(65535/3)ではwarningsが現れるだけでvarcharは自動的にmediumtextタイプになります.
    注意深い友达は、上から文字セットshow variabels like "char%";を見たことに気づいたかもしれません.次に、クライアント文字セットがdatabaseと異なる場合について説明します.
    N<=2181 2の正常な状況に戻ります.
    CREATE TABLE `tc_utf8` (
      `c1` int(11) NOT NULL AUTO_INCREMENT,
      `c2` char(30) DEFAULT NULL,
      `c3` varchar(30) DEFAULT NULL,
      PRIMARY KEY (`c1`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

    いくつかのデータを挿入します.
    mysql> set names utf8;
    mysql> insert into tc_utf8(c2,c3) values('en_30',repeat('a',30));
    Query OK, 1 rows affected (17.87 sec)
    
    mysql> insert into tc_utf8(c2,c3) values('en_31',repeat('b',31));
    Query OK, 1 rows affected, 1 warnings (0.10 sec)
    
    mysql> show warnings;
    +---------+------+-----------------------------------------+
    | Level   | Code | Message                                 |
    +---------+------+-----------------------------------------+
    | Warning | 1265 | Data truncated for column 'c3' at row 1 |
    +---------+------+-----------------------------------------+
    1 rows in set (0.14 sec)
    
    mysql> insert into tc_utf8(c2,c3) values('zh_30',repeat(' ',30));
    Query OK, 1 rows affected (0.18 sec)
    
    mysql> insert into tc_utf8(c2,c3) values('zh_31',repeat(' ',31));
    Query OK, 1 rows affected, 1 warnings (0.09 sec)
    
        ,       
    
    ysql> select c2,c3,length(c3),char_length(c3) from tc_utf8;
    +-------+------------+-----------------+------------------------------------------------------------------------+
    | c2    | length(c3) | char_length(c3) | c3                                                                     |
    +-------+------------+-----------------+------------------------------------------------------------------------+
    | en_30 |         30 |              30 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa                                         |
    | en_31 |         30 |              30 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb                                         |
    | zh_30 |         90 |              30 |                                |
    | zh_31 |         90 |              30 |                                |
    +-------+------------+-----------------+------------------------------------------------------------------------+
    4 rows in set (0.00 sec)

    上のen_30はinsertを表すときに30文字の英語文字を格納します.30個のaが30バイト、30個の漢字が90バイトを占め、30を超えると遮断されることが見られ、文章の冒頭の説が確認された.
    mysql> set names latin1;
    
    mysql> insert into tc_utf8(c2,c3) values('zh_30_latin1',repeat(' ',30));
    Query OK, 1 rows affected, 1 warnings (0.10 sec)
    
    mysql> show warnings;
    +---------+------+-----------------------------------------+
    | Level   | Code | Message                                 |
    +---------+------+-----------------------------------------+
    | Warning | 1265 | Data truncated for column 'c3' at row 1 |
    +---------+------+-----------------------------------------+
    1 rows in set (0.14 sec)
    
    mysql> insert into tc_utf8(c2,c3) values('zh_10_latin1',repeat(' ',10));
    Query OK, 1 rows affected (0.10 sec)
    
    mysql> insert into tc_utf8(c2,c3) values('zh_10_latin1',repeat(' ',10));
    Query OK, 1 rows affected (0.11 sec)
    
    mysql> insert into tc_utf8(c2,c3) values('zh_11_latin1',repeat(' ',11));
    Query OK, 1 rows affected, 1 warnings (0.12 sec)
    
      

    以上の実験でdb tableはutf 8であるが,クライアント接続時にlatin 1を用い,非厳格モードでvarchar(30)は漢字10個しか保存できず,余分な末尾が切断された.
    バイトを占有する場合を見てみましょう.(2,3行の文字化けしは予想外でした)
    mysql> select c1,c2,c3,length(c3),char_length(c3) from tc_utf8;
    +----+--------------+--------------------------------+------------+-----------------+
    | c1 | c2           | c3                             | length(c3) | char_length(c3) |
    +----+--------------+--------------------------------+------------+-----------------+
    | 1  | en_30        | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | 30         | 30              |
    | 2  | en_31        | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb | 30         | 30              |
    | 3  | zh_30        | ?????????????????????????????? | 90         | 30              |
    | 4  | zh_31        | ?????????????????????????????? | 90         | 30              |
    | 5  | zh_30_latin1 |            | 60         | 30              |
    | 6  | zh_10_latin1 |            | 60         | 30              |
    | 7  | zh_10_latin1 |            | 80         | 30              |
    | 9  | zh_11_latin1 |            | 80         | 30              |
    +----+--------------+--------------------------------+------------+-----------------+
    8 rows in set (0.14 sec)

    char_が見えますlength関数で算出した中、英語の文字の個数はすべて30で、しかし1つの“中”は6バイトを占めて、1つの“文”は8バイトを占めて、とても驚いて、この中間は数回の符号化の変換の過程があって、興味があって参考にすることができますhttp://mysql.rjweb.org/doc.php/charcollああ、シミュレーションできます.
    厳格モードではそれほど複雑ではないので、できるだけSTRICT_を使いますTRANS_TABLESは、予期せぬ事態が生産環境に持ち込まれることを避ける.初期の設計では、クライアントとデータベースの文字セットが一致していることを維持します.
    リファレンス
  • MySQL manual:The CHAR and VARCHAR Types
  • MySQL文字セットガイド--進級編V 0.7
  • MySQL文字セットと校正規則
  • MySQL String Length
  • http://sunny90.com/a/database/2014/0819/24.html

  • リンク先:http://seanlook.com/2016/04/28/mysql-char-varchar-set/