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
型を使用して長さの制限を設定してください。デフォルトでは、VARCHAR
は最大255文字までに制限されており、その制限は宣言の直後の括弧内に暗黙的に指定されなければなりません。すなわち、VARCHAR(200)
は200文字までに制限します。
テーブルでTEXT
またはBLOB
関連タイプを使用していなくても、エラー1170が表示されることがあります。主キーとしてVARCHAR
列を指定したが、その長さまたは文字サイズを誤って設定した場合などに発生します。 VARCHAR
は最大256文字までしか受け入れられないため、VARCHAR(512)
のようなものはMySQLにVARCHAR(512)
をSMALLTEXT
データ型に自動変換させます。その後、列が主キーとして使用されたりユニークまたは非ユニークとして使用されるとエラーになります。ユニークインデックスこの問題を解決するには、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
を使用するため、1文字あたり最大で3
バイト必要)
列全体をPRIMARY KEY
にする必要がある場合は、SHA1
またはMD5
ハッシュを計算し、それをPRIMARY KEY
として使用します。
テーブル変更要求でキーの長さを指定できます。
alter table authors ADD UNIQUE(name_first(20), name_second(20));
MySQLはBLOB
、TEXT
およびlong VARCHAR
カラムのフル値のインデックス化を許可していません。それらに含まれるデータは巨大になる可能性があり、暗黙のうちにDBインデックスは大きくなるため、インデックスの恩恵を受けないからです。
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をインデックスに追加し、最小のインデックスを定義するとします。 numberNが最良のインデックス選択性を生み出します。
まず、最も頻繁に現れる姓を特定しましょう。
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)
これはとても良い結果です。これは、最初の10文字だけをインデックス付けすることで、列last_name
にインデックスを作成できることを意味します。テーブル定義列のlast_name
はVARCHAR(16)
として定義されています。これはエントリごとに6バイト(姓にUTF8文字がある場合はそれ以上)を節約したことを意味します。このテーブルには、1637個の異なる値に6バイトを掛けたものが約9KBです。テーブルに何百万もの行が含まれている場合、この数がどのように増加するかを想像してください。
あなたは私の記事でNの数を計算する他の方法を読むことができます MySQLのプレフィックスインデックス .
alter table authors ADD UNIQUE(name_first(767), name_second(767));
NOTE:767は、blob/textインデックスの処理中にMySQLがカラムにインデックスを付けるまでの文字数制限です。
参照: http://dev.mysql.com/doc/refman/5.7/ja/innodb-restrictions.html
主キーとして長い値を持たないでください。それはあなたのパフォーマンスを破壊するでしょう。 mysqlマニュアルのセクション13.6.13「InnoDBパフォーマンスチューニングとトラブルシューティング」を参照してください。
代わりに、(auto_incrementを使用して)プライマリとして代理intキーを使用し、セカンダリUNIQUEとしてあなたのloongキーを使用します。
これを処理するもう1つの優れた方法は、ユニーク制約なしでTEXTフィールドを作成し、ユニークでTEXTフィールドの要約(MD5、SHA1など)を含む兄弟VARCHARフィールドを追加することです。 TEXTフィールドを挿入または更新するときにTEXTフィールド全体のダイジェストを計算して保存すると、(先頭部分ではなく)TEXTフィールド全体に対する一意性の制約があり、すばやく検索できます。
255文字では足りない場合にオーバーフローを保持するために別のvarChar(255)列(デフォルトではnullではない空の文字列)を追加し、両方の列を使用するようにこのPKを変更します。しかし、これはうまく設計されたデータベーススキーマのようには思えませんが、より多くの正規化のためにリファクタリングすることを視野に入れて、データモデラにあなたが持っているものを見るように勧めます。
テキスト型の列を持つテーブルにインデックスを追加すると、このエラーが発生しました。各テキストタイプに使用するサイズを宣言する必要があります。
サイズの量をかっこ内に入れる()
使用するバイト数が多すぎる場合は、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));
4バイトで、絵文字を格納することもできるutf8mb4(これ以上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 = Antelopeではない必要)の最大インデックス列サイズは3072です。innodb_large_prefix = 1の場合、MySQL> = 5.6.3以降で使用可能ですMySQL <= 5.7.6、MySQLのデフォルトで有効> = 5.7.7)。そのため、この場合はインデックス付きカラムにutf8mb4にVARCHAR(768)(古いutf8にVARCHAR(1024))を使用できます。オプションinnodb_large_prefixは、その動作がMySQL 8に組み込まれているため(このバージョンではオプションが削除されているため)、5.7.7から非推奨になりました。
また、このフィールドでインデックスを使用したい場合は、MyISAMストレージエンジンとFULLTEXTインデックスタイプを使用する必要があります。
この問題を解決するには、CREATE TABLE
ステートメントで、列作成定義の後に制約UNIQUE ( problemtextfield(300) )
を追加して、例えばkey
フィールドに300
文字のTEXT
の長さを指定します。その場合、problemtextfield
TEXT
フィールドの最初の300
文字は固有である必要があり、それ以降の相違は無視されます。
Mysql edit table
->列タイプをvarchar(45)
に変更します。
インデックスを作成するには、列タイプをvarchar
またはinteger
に変更する必要があります。
こんな感じ
@Id
@Column(name = "userEmailId", length=100)
private String userEmailId;