452

varchar(255) である主キーを持つテーブルがあります。255 文字では不十分な場合があります。フィールドをテキストに変更しようとしましたが、次のエラーが発生します。

BLOB/TEXT column 'message_id' used in key specification without a key length

どうすればこれを修正できますか?

編集:このテーブルには、複数の列を持つ複合主キーがあることも指摘する必要があります。

4

18 に答える 18

693

このエラーは、MySQL が BLOB またはTEXT列の最初の N 文字のみをインデックス化できるために発生します。そのため、エラーは主に、 または BLOB のフィールド/列タイプがある場合、またはそれらが、、、 、などのタイプTEXTに属している場合に発生し、主キーまたはインデックスを作成しようとします。長さの値が完全であるかどうかに関係なく、MySQL は列の一意性を保証できません。これは、列が可変で動的なサイズであるためです。そのため、 or型をインデックスとして使用する場合、MySQL がキーの長さを決定できるように N の値を指定する必要があります。ただし、MySQL はまたはのキー長制限をサポートしていません。単に機能しません。TEXTBLOBTINYBLOBMEDIUMBLOBLONGBLOBTINYTEXTMEDIUMTEXTLONGTEXTBLOBTEXTBLOBTEXTTEXTBLOBTEXT(88)

列が既に一意の制約またはインデックスとして定義されている状態で、テーブルの列をnon-TEXTandnon-BLOBなどの型からor型VARCHARENUM変換しようとすると、エラーがポップアップ表示されます。Alter Table SQL コマンドは失敗します。TEXTBLOB

この問題の解決策は、インデックスまたは一意の制約からTEXTまたは列を削除するか、別のフィールドを主キーとして設定することです。BLOBそれができず、TEXTまたはBLOB列に制限を設けたい場合は、 VARCHARtype を使用して長さの制限を設定してみてください。デフォルトでVARCHARは、 は最大 255 文字に制限されており、その制限は、宣言の直後にブラケット内で暗黙的に指定する必要があります。つまり、VARCHAR(200)長さは 200 文字のみに制限されます。

TEXTまたは関連するタイプをテーブルで使用していなくてもBLOB、エラー 1170 が表示される場合があります。VARCHAR列を主キーとして指定しているが、その長さや文字サイズを誤って設定した場合などに発生します。VARCHAR最大 256 文字しか受け入れられないため、 MySQL にデータ型へのVARCHAR(512)自動変換を強制するようなものはすべて、列が主キーまたは一意または非一意のインデックスとして使用されている場合、キーの長さに関するエラー 1170 で失敗します。この問題を解決するには、フィールドのサイズとして 256 未満の数値を指定します。VARCHAR(512)SMALLTEXTVARCHAR

参照: MySQL エラー 1170 (42000): BLOB/TEXT カラムがキーの長さのないキー仕様で使用される

于 2009-12-01T15:55:17.710 に答える
105

TEXT索引付けする列の先頭部分を定義する必要があります。

InnoDBインデックス キーあたりのバイト数に制限があり、768それより長いインデックスを作成することはできません。

これはうまくいきます:

CREATE TABLE t_length (
      mydata TEXT NOT NULL,
      KEY ix_length_mydata (mydata(255)))
    ENGINE=InnoDB;

キー サイズの最大値は、列の文字セットに依存することに注意してください。これ767は、シングルバイト文字セットのような文字であり、文字LATIN1のみ( 1 文字あたり最大バイト数を必要とする用途のみ) の文字です。255UTF8MySQLBMP3

列全体を にする必要がある場合はPRIMARY KEY、計算SHA1またはMD5ハッシュして、 として使用しPRIMARY KEYます。

于 2009-12-01T15:57:57.533 に答える
70

次のように、alter table リクエストでキーの長さを指定できます。

alter table authors ADD UNIQUE(name_first(20), name_second(20));
于 2011-07-12T16:51:08.707 に答える
25

含まれるデータが巨大になる可能性があり、暗黙的に DB インデックスが大きくなり、インデックスのメリットがないため、MySQL はBLOBTEXTおよび 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 のプレフィックス インデックスの投稿で読むことができます。

于 2015-11-22T13:45:18.980 に答える
6

これに対処するもう 1 つの優れた方法は、一意の制約なしで TEXT フィールドを作成し、一意で TEXT フィールドのダイジェスト (MD5、SHA1 など) を含む兄弟 VARCHAR フィールドを追加することです。TEXT フィールドを挿入または更新するときに、TEXT フィールド全体のダイジェストを計算して保存すると、TEXT フィールド全体 (一部の先頭部分ではなく) に対する一意性制約があり、すばやく検索できます。

于 2015-09-27T21:52:35.250 に答える
3

主キーとして長い値を持たないでください。それはあなたのパフォーマンスを破壊します。mysqlのマニュアルのセクション13.6.13「InnoDBパフォーマンスのチューニングとトラブルシューティング」を参照してください。

代わりに、サロゲートintキーをプライマリ(auto_incrementを使用)として使用し、loongキーをセカンダリUNIQUEとして使用します。

于 2012-03-01T10:29:49.540 に答える
2

255 文字では不十分な場合にオーバーフローを保持するために、別の varChar(255) 列 (デフォルトでは null ではない空の文字列) を追加し、両方の列を使用するようにこの PK を変更します。ただし、これは適切に設計されたデータベース スキーマのようには思えません。より正規化するためにリファクタリングする目的で、データ モデラーに自分の持っているものを見てもらうことをお勧めします。

于 2009-12-01T16:01:10.263 に答える
1


データ型が TEXT の場合 - VARCHARソリューション 1: クエリに変更する必要があります

ALTER TABLE table_name MODIFY COLUMN col_name datatype;
ALTER TABLE my_table MODIFY COLUMN my_col VARCHAR(255);

解決策 2: GUI (MySQL ワークベンチ)
step1 - テキスト ボックスに書き込む ここに画像の説明を入力

step2 - データ型の編集、適用 ここに画像の説明を入力

于 2021-01-28T07:04:00.780 に答える