varchar(255)である主キーを持つテーブルがあります。255文字では不十分な場合もあります。フィールドをテキストに変更しようとしましたが、次のエラーが発生しました。
BLOB/TEXT column 'message_id' used in key specification without a key length
どうすれば修正できますか?
編集:私はまた、このテーブルには複数の列を持つ複合主キーがあることを指摘する必要があります。
varchar(255)である主キーを持つテーブルがあります。255文字では不十分な場合もあります。フィールドをテキストに変更しようとしましたが、次のエラーが発生しました。
BLOB/TEXT column 'message_id' used in key specification without a key length
どうすれば修正できますか?
編集:私はまた、このテーブルには複数の列を持つ複合主キーがあることを指摘する必要があります。
回答:
エラーが発生するのは、MySQLがBLOBまたはTEXT
列の最初のN文字しかインデックスに登録できないためです。主にフィールド/列のタイプがある場合に起こるエラーは、だから、TEXT
またはBLOBまたはに属するTEXT
かBLOB
のようなタイプはTINYBLOB
、MEDIUMBLOB
、LONGBLOB
、TINYTEXT
、MEDIUMTEXT
、とLONGTEXT
あなたは主キーまたはインデックスを作成しようとしています。完全BLOB
またはTEXT
長さの値がない場合、MySQLは可変で動的なサイズであるため、列の一意性を保証できません。したがって、インデックスとして使用BLOB
またはTEXT
タイプする場合、MySQLがキーの長さを決定できるようにNの値を指定する必要があります。しかし、MySQLは上のキーの長さ制限をサポートしていませんTEXT
かBLOB
。TEXT(88)
単に機能しません。
あなたからテーブル列を変換しようとするとエラーがポップアップ表示されますnon-TEXT
し、non-BLOB
などと入力VARCHAR
し、ENUM
へTEXT
たりBLOB
、すでにユニーク制約またはインデックスとして定義されて列で、タイプ。テーブルの変更SQLコマンドは失敗します。
この問題の解決策は、インデックスまたは一意の制約からTEXT
またはBLOB
列を削除するか、別のフィールドを主キーとして設定することです。それを行うことができず、TEXT
またはBLOB
列にVARCHAR
制限を設定する場合は、type を使用して長さに制限を設定してください。デフォルトでVARCHAR
は、最大255文字に制限されており、その制限は宣言の直後にブラケット内で暗黙的に指定する必要があります。つまりVARCHAR(200)
、200文字に制限されます。
場合によっては、テーブルで使用していないTEXT
か、BLOB
関連する型を使用していても、エラー1170が表示されることがあります。VARCHAR
列を主キーとして指定したが、長さや文字サイズを誤って設定した場合などに発生します。VARCHAR
だけのような何もして、256文字まで受け入れることができVARCHAR(512)
、自動変換するために、MySQLを強制するVARCHAR(512)
にはSMALLTEXT
列が主キーまたは一意または非一意のインデックスとして使用されている場合、その後キーの長さのエラー1170で失敗したデータ型、。この問題を解決するには、VARCHAR
フィールドのサイズとして256未満の数値を指定します。
TEXT
インデックスを作成する列の先頭部分を定義する必要があります。
InnoDB
768
インデックスキーごとのバイト数の制限があり、それより長いインデックスを作成することはできません。
これはうまくいきます:
CREATE TABLE t_length (
mydata TEXT NOT NULL,
KEY ix_length_mydata (mydata(255)))
ENGINE=InnoDB;
キーサイズの最大値は列の文字セットによって異なることに注意してください。これ767
は、シングルバイト文字セットのような文字であり、の文字LATIN1
のみ255
ですUTF8
(文字ごとに最大でバイトを必要とするMySQL
使用のみ)BMP
3
列全体をにする必要がある場合はPRIMARY KEY
、計算SHA1
またはMD5
ハッシュしてとして使用しPRIMARY KEY
ます。
REDUNDANT
か、COMPACT
行フォーマット。たとえば、utf8mb3文字セットと各文字の最大3バイトを想定して、TEXT
またはVARCHAR
列で255文字を超える列プレフィックスインデックスでこの制限に達する可能性があります。 REDUNDANT
そしてCOMPACT
この答えが与えられた時点で入手可能な唯一の形式でした。
次のように、テーブルの変更リクエストでキーの長さを指定できます。
alter table authors ADD UNIQUE(name_first(20), name_second(20));
MySQLは、の完全な値と長い列にインデックスを付けることを許可しません。これはBLOB
、それらに含まれるデータが巨大になる可能性があり、暗黙的にDBインデックスが大きくなるため、インデックスのメリットがないことを意味します。TEXT
VARCHAR
MySQLでは、インデックスを付ける最初のN文字を定義する必要があります。コツは、十分な選択性を提供するのに十分な長さで、スペースを節約するのに十分短いNを選択することです。プレフィックスは、インデックスを列全体にインデックス付けした場合と同じくらい役立つように十分な長さにする必要があります。
さらに進む前に、いくつかの重要な用語を定義しましょう。インデックスの選択性は、個別のインデックス値の合計と行の総数の比率です。テストテーブルの例を次に示します。
+-----+-----------+
| id | value |
+-----+-----------+
| 1 | abc |
| 2 | abd |
| 3 | adg |
+-----+-----------+
最初の文字(N = 1)のみにインデックスを付けると、インデックステーブルは次のテーブルのようになります。
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| a | 1,2,3 |
+---------------+-----------+
この場合、インデックスの選択性はIS = 1/3 = 0.33と等しくなります。
インデックス付き文字の数を2(N = 2)に増やすとどうなるかを見てみましょう。
+---------------+-----------+
| indexedValue | rows |
+---------------+-----------+
| ab | 1,2 |
| ad | 3 |
+---------------+-----------+
このシナリオではIS = 2/3 = 0.66です。これは、インデックスの選択性を高めたことを意味しますが、インデックスのサイズも増やしました。トリックは、最大のインデックス選択性をもたらす最小数Nを見つけることです。
データベーステーブルの計算には2つの方法があります。このデータベースダンプのデモを行います。
テーブルemployeesの列last_nameをインデックスに追加し、インデックスの選択性が最も高くなる最小の数Nを定義するとします。
最初に、最も頻繁に使用する姓を特定しましょう。
select count(*) as cnt, last_name
from employees
group by employees.last_name
order by cnt
+-----+-------------+
| cnt | last_name |
+-----+-------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Farris |
| 222 | Sudbeck |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Neiman |
| 218 | Mandell |
| 218 | Masada |
| 217 | Boudaillier |
| 217 | Wendorf |
| 216 | Pettis |
| 216 | Solares |
| 216 | Mahnke |
+-----+-------------+
15 rows in set (0.64 sec)
ご覧のように、姓のババが最も頻繁に使用されます。次に、5文字のプレフィックスで始まる、最も頻繁に発生するlast_nameプレフィックスを見つけます。
+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa |
| 758 | Mande |
| 711 | Schwa |
| 562 | Angel |
| 561 | Gecse |
| 555 | Delgr |
| 550 | Berna |
| 547 | Peter |
| 543 | Cappe |
| 539 | Stran |
| 534 | Canna |
| 485 | Georg |
| 417 | Neima |
| 398 | Petti |
| 398 | Duclo |
+-----+--------+
15 rows in set (0.55 sec)
すべての接頭辞の出現回数がはるかに多いため、値が前の例とほぼ同じになるまで、番号Nを増やす必要があります。
N = 9の結果は次のとおりです
select count(*) as cnt, left(last_name,9) as prefix
from employees
group by prefix
order by cnt desc
limit 0,15;
+-----+-----------+
| cnt | prefix |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudailli |
| 216 | Cummings |
| 216 | Pettis |
+-----+-----------+
N = 10の結果を次に示します。
+-----+------------+
| cnt | prefix |
+-----+------------+
| 226 | Baba |
| 223 | Coorg |
| 223 | Gelosh |
| 222 | Sudbeck |
| 222 | Farris |
| 221 | Adachi |
| 220 | Osgood |
| 218 | Mandell |
| 218 | Neiman |
| 218 | Masada |
| 217 | Wendorf |
| 217 | Boudaillie |
| 216 | Cummings |
| 216 | Pettis |
| 216 | Solares |
+-----+------------+
15 rows in set (0.56 sec)
これは非常に良い結果です。これは、last_name
最初の10文字のみにインデックスを付けて、列にインデックスを作成できることを意味します。テーブル定義では、列last_name
はとして定義されています。VARCHAR(16)
これは、エントリごとに6バイト(姓にUTF8文字がある場合はそれ以上)を節約したことを意味します。この表には、6バイトを掛けた1637の異なる値があり、約9KBです。テーブルに数百万の行が含まれている場合、この数がどのように増えるかを想像してください。
Nの数を計算する他の方法については、MySQLのポストプレフィックスインデックスを参照してください。
テキストタイプの列を持つテーブルにインデックスを追加すると、このエラーが発生しました。各テキストタイプに使用するサイズを宣言する必要があります。
括弧内にサイズ量を入れてください()
使用するバイト数が多すぎる場合は、varcharのかっこ内でサイズを宣言して、インデックス作成に使用する量を減らすことができます。これは、varchar(1000)のような型のサイズを宣言した場合でも同じです。他のユーザーが言っているように、新しいテーブルを作成する必要はありません。
インデックスを追加する
alter table test add index index_name(col1(255),col2(255));
一意のインデックスを追加する
alter table test add unique index_name(col1(255),col2(255));
alter table authors ADD UNIQUE(name_first(767), name_second(767));
注:767は、MySQLがblob / textインデックスを処理するときに列にインデックスを付ける文字数の上限です。
参照:http : //dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html
これに対処するもう1つの優れた方法は、一意の制約なしでTEXTフィールドを作成し、一意で、TEXTフィールドのダイジェスト(MD5、SHA1など)を含む兄弟VARCHARフィールドを追加することです。TEXTフィールドを挿入または更新するときに、TEXTフィールド全体のダイジェストを計算して保存すると、すばやく検索できる(一部の先行部分ではなく)テキストフィールド全体に一意性制約が適用されます。
また、このフィールドでインデックスを使用する場合は、MyISAMストレージエンジンとFULLTEXTインデックスタイプを使用する必要があります。
これまでのところ誰も言及していません... utf8mb4は4バイトで、絵文字も格納できます(3バイトのutf8はこれ以上使用しIncorrect string value: \xF0\x9F\x98\...
ないでください)。通常のVARCHAR(255)ではなくVARCHAR( 191) utf8mb4とVARCHAR(255)の場合、データの同じ部分がページ外に格納され、列VARCHAR(255)にはインデックスを作成できませんが、VARCHAR(191)には作成できるためです。これは、ROW_FORMAT = COMPACTまたはROW_FORMAT = REDUNDANTの最大インデックス列サイズが767バイトであるためです。
新しい行フォーマットの場合、ROW_FORMAT = DYNAMICまたはROW_FORMAT = COMPRESSED(新しいファイルフォーマットinnodb_file_format = Barracudaではなく、Antelopeが必要)の最大インデックス列サイズは3072です。これは、MySQL> = 5.6.3以降、innodb_large_prefix = 1の場合に使用できます(デフォルトでは無効になっています) MySQL <= 5.7.6、MySQLのデフォルトで有効> = 5.7.7)。したがって、この場合、インデックス付きの列にutf8mb4にはVARCHAR(768)(古いutf8にはVARCHAR(1024))を使用できます。オプションinnodb_large_prefixは、その動作が組み込みのMySQL 8(このバージョンではオプションが削除されている)であるため、5.7.7以降非推奨です。
UNIQUE
ですか、それとも複数のキーがあるのですか?