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 文字のみをインデックス化できるために発生します。そのため、エラーは主に、 または BLOB のフィールド/列タイプがある場合、またはそれらが、、、 、などのタイプTEXT
に属している場合に発生し、主キーまたはインデックスを作成しようとします。長さの値が完全であるかどうかに関係なく、MySQL は列の一意性を保証できません。これは、列が可変で動的なサイズであるためです。そのため、 or型をインデックスとして使用する場合、MySQL がキーの長さを決定できるように N の値を指定する必要があります。ただし、MySQL はまたはのキー長制限をサポートしていません。単に機能しません。TEXT
BLOB
TINYBLOB
MEDIUMBLOB
LONGBLOB
TINYTEXT
MEDIUMTEXT
LONGTEXT
BLOB
TEXT
BLOB
TEXT
TEXT
BLOB
TEXT(88)
列が既に一意の制約またはインデックスとして定義されている状態で、テーブルの列をnon-TEXT
andnon-BLOB
などの型からor型VARCHAR
にENUM
変換しようとすると、エラーがポップアップ表示されます。Alter Table SQL コマンドは失敗します。TEXT
BLOB
この問題の解決策は、インデックスまたは一意の制約からTEXT
または列を削除するか、別のフィールドを主キーとして設定することです。BLOB
それができず、TEXT
またはBLOB
列に制限を設けたい場合は、 VARCHAR
type を使用して長さの制限を設定してみてください。デフォルトでVARCHAR
は、 は最大 255 文字に制限されており、その制限は、宣言の直後にブラケット内で暗黙的に指定する必要があります。つまり、VARCHAR(200)
長さは 200 文字のみに制限されます。
TEXT
または関連するタイプをテーブルで使用していなくてもBLOB
、エラー 1170 が表示される場合があります。VARCHAR
列を主キーとして指定しているが、その長さや文字サイズを誤って設定した場合などに発生します。VARCHAR
最大 256 文字しか受け入れられないため、 MySQL にデータ型へのVARCHAR(512)
自動変換を強制するようなものはすべて、列が主キーまたは一意または非一意のインデックスとして使用されている場合、キーの長さに関するエラー 1170 で失敗します。この問題を解決するには、フィールドのサイズとして 256 未満の数値を指定します。VARCHAR(512)
SMALLTEXT
VARCHAR
参照: MySQL エラー 1170 (42000): BLOB/TEXT カラムがキーの長さのないキー仕様で使用される
TEXT
索引付けする列の先頭部分を定義する必要があります。
InnoDB
インデックス キーあたりのバイト数に制限があり、768
それより長いインデックスを作成することはできません。
これはうまくいきます:
CREATE TABLE t_length (
mydata TEXT NOT NULL,
KEY ix_length_mydata (mydata(255)))
ENGINE=InnoDB;
キー サイズの最大値は、列の文字セットに依存することに注意してください。これ767
は、シングルバイト文字セットのような文字であり、文字LATIN1
のみ( 1 文字あたり最大バイト数を必要とする用途のみ) の文字です。255
UTF8
MySQL
BMP
3
列全体を にする必要がある場合はPRIMARY KEY
、計算SHA1
またはMD5
ハッシュして、 として使用しPRIMARY KEY
ます。
次のように、alter table リクエストでキーの長さを指定できます。
alter table authors ADD UNIQUE(name_first(20), name_second(20));
含まれるデータが巨大になる可能性があり、暗黙的に DB インデックスが大きくなり、インデックスのメリットがないため、MySQL はBLOB
、TEXT
および longカラムの完全な値のインデックス作成を許可しません。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)
ご覧のとおり、 Babaという姓が最も頻繁に使用されます。次に、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 文字のみをインデックス付けして、列にインデックスを作成できることを意味します。テーブル定義の columnlast_name
は として定義されていVARCHAR(16)
ます。これは、エントリごとに 6 バイト (姓に UTF8 文字がある場合はそれ以上) を節約したことを意味します。このテーブルには、1637 個の異なる値があり、6 バイトを掛けると約 9KB になります。テーブルに何百万もの行が含まれている場合、この数がどのように増加するか想像してみてください。
Nの数を計算する他の方法は、MySQL のプレフィックス インデックスの投稿で読むことができます。
これに対処するもう 1 つの優れた方法は、一意の制約なしで TEXT フィールドを作成し、一意で TEXT フィールドのダイジェスト (MD5、SHA1 など) を含む兄弟 VARCHAR フィールドを追加することです。TEXT フィールドを挿入または更新するときに、TEXT フィールド全体のダイジェストを計算して保存すると、TEXT フィールド全体 (一部の先頭部分ではなく) に対する一意性制約があり、すばやく検索できます。
主キーとして長い値を持たないでください。それはあなたのパフォーマンスを破壊します。mysqlのマニュアルのセクション13.6.13「InnoDBパフォーマンスのチューニングとトラブルシューティング」を参照してください。
代わりに、サロゲートintキーをプライマリ(auto_incrementを使用)として使用し、loongキーをセカンダリUNIQUEとして使用します。
255 文字では不十分な場合にオーバーフローを保持するために、別の varChar(255) 列 (デフォルトでは null ではない空の文字列) を追加し、両方の列を使用するようにこの PK を変更します。ただし、これは適切に設計されたデータベース スキーマのようには思えません。より正規化するためにリファクタリングする目的で、データ モデラーに自分の持っているものを見てもらうことをお勧めします。