TL;DR: wp_options テーブルにプライマリキーが欠落していると、MySQL が option_id の自動インクリメントを停止し、新しい行は option_id = 0 で書き込まれます。WordPress は引き続き動作しますが、エクスポート、移行、Staging への PUSH のたびに重複キーエラーで失敗し、MySQL がキーを使えなくなるためテーブルへのクエリも遅くなります。最速の修正方法: データベースを Backup し、重複した option_id の値をそれぞれ一意になるよう振り直してから、ALTER TABLE wp_options ADD PRIMARY KEY (option_id) を実行し、AUTO_INCREMENT を復元します。修復はすべて phpMyAdmin で、または素の SQL で行えます。Plugin は不要です。
Contents
特定の状況下では、wp_options テーブル (または他の任意のテーブル) がプライマリキーのインデックスを失うことがあります。正確なきっかけが明らかになることはまれです。WP STAGING のサポートチケットでは、あるサーバーから別のサーバーへ手動で移行したデータベースや、MySQL バージョン間の切り替え、InnoDB と MyISAM ストレージエンジン間の切り替えなど、すべてのケースを考慮していないツールで移動したデータベースで最もよく見られます。
明確にしておきます: WP STAGING はこのエラーの原因ではありません。WP STAGING は、プライマリキーのないコアテーブルを見つけたときに WordPress 管理ダッシュボードに目立つ警告を表示することで、検出のお手伝いをするだけです。早めにお知らせするのは、これが重大で陰湿な問題だからです。サイトは何の問題もないかのように読み込まれ続けるため、移行や Backup が失敗するまで気付きません。そしてその頃には、テーブルが数百もの壊れた行を抱えているかもしれません。未修正のまま放置するほど重複行が蓄積し、修復の作業量も増えていきます。
プライマリキーとは何か、なぜ wp_options に必要なのか
プライマリキーとは、テーブル内のすべての行を一意に識別する列 (または列の組み合わせ) です。標準的な WordPress のインストールでは、wp_options テーブルはプライマリキーとして option_id を使用します。option_id は bigint(20) unsigned NOT NULL auto_increment として定義されており、これはデータベースが新しい行ごとに次の未使用の番号を自動的に割り当て、2 つの行が同じ値を共有しないことを保証することを意味します。
そのキーが消えると、2 つのことが壊れます:
- 自動インクリメントが停止する。 プライマリキーがないと、MySQL は
option_idをインクリメントしなくなります。新しい行はすべてデフォルト値の0で挿入されます。下の最初の例は、正常なシーケンスがどのようなものかを示しています:そして、キーが失われて新しい行がoption_id = 0で積み上がると、同じ列は次のようになります: - エクスポートと移行が失敗する。 プライマリキーの列は一意の値を保持しなければなりません。これらの行をエクスポートして別のデータベースにインポートした瞬間に、MySQL は
Cannot insert duplicate keyのようなエラーで重複を拒否し、インポートは途中で停止します。これが、キーが欠落しているときに WP STAGING や他のすべての移行 Plugin がデータベース転送を完了できない理由です。Staging サイトから本番への PUSH は、重複した0の行が書き込まれるまさにその時点で失敗します。
より目立たないコストもあります。wp_options は WordPress で最も読み取りの多いテーブルの 1 つです。なぜなら、自動読み込み (autoload) オプションはほぼすべてのリクエストで取得されるからです。私たちのテストでは、プライマリキーが欠落していると、本来ならキーを使うはずの検索で MySQL がフルテーブルスキャンにフォールバックするため、通常のページ読み込みに測定可能なオーバーヘッドが加わります。wp_options がより広いスキーマの中でどう位置づけられるかの背景については、WordPress データベースに不可欠なテーブルのガイドをご覧ください。
プライマリキーが本当に欠落しているか確認する方法
何かを変更する前に、これが本当にあなたの問題なのかを確認してください。phpMyAdmin や Adminer などのデータベースツールを開き、WordPress データベースを選択して、次を実行します:
SHOW CREATE TABLE wp_options;
正常なテーブルでは、出力に PRIMARY KEY (option_id) のような行が含まれ、option_id 列に AUTO_INCREMENT が付いています。両方とも欠落している場合、キーは失われています。インデックスを直接一覧することもできます:
SHOW INDEX FROM wp_options;
キーが無傷のテーブルでは、Key_name が PRIMARY である行が返されます。その行がなければ、プライマリキーはありません。
このスクリーンショットは、option_id 列にプライマリキーが設定された通常の wp_options テーブルを示しています:

この 2 つ目のスクリーンショットは、プライマリキーが欠落した同じテーブルを示しています:

すでにいくつの行が影響を受けているかを確認するには、重複を数えます:
SELECT option_id, COUNT(*) AS copies
FROM wp_options
GROUP BY option_id
HAVING copies > 1;
option_id = 0 でカウントが 1 を超えるグループがあれば、キーを復元する前に振り直す必要のある壊れた行があることが確認できます。
インストールがカスタムのテーブル接頭辞を使用している場合は (例: wp_xyz_options)、全体を通して wp_options を実際のテーブル名に置き換えてください。
始める前に: データベースを Backup する
以下の手順はすべてデータベースを直接変更するため、まずは完全な Backup を取り、それをサーバーの外にダウンロードしてください。何か問題が起きた場合に、復元できるクリーンなコピーが必要です。WP STAGING の Backup、phpMyAdmin のエクスポート、mysqldump のいずれでも構いません。これは、本番ではなく Staging のコピーで作業する良い機会でもあります: サイトをクローンし、そこでテーブルを修復し、結果を確認してから、同じ修正を本番のデータベースに適用してください。
phpMyAdmin で欠落したプライマリキーを修正する
素の SQL よりもグラフィカルなインターフェースを好む場合、phpMyAdmin は Structure タブから修復全体を処理できます。
- phpMyAdmin または Adminer を開き、
wp_optionsテーブルに移動します。 - まず重複した ID に対処します。
option_id列の既存の最大値を取り、0の行を 1 つずつ振り直して、すべての値が再び一意になるようにします。このスクリーンキャストは振り直しの方法を示しています:
- テーブルのインデックスエディターを開きます:

option_idをプライマリキーとして設定します:
Duplicate entry '0' for key 'PRIMARY'というエラーが表示された場合、まだ重複した ID がテーブルに残っています:
- 残った重複を見つけ、どれも繰り返さないように値をカウントアップしてから、プライマリキーを再度追加します。成功したら、
option_idの自動インクリメントを再び有効にして、今後の行が正しく番号付けされるようにします。
SQL で欠落したプライマリキーを修正する
SQL コンソールに慣れているなら、同じ修復は 3 つのステートメントで済みます。WordPress データベースに対して順番に実行してください。
まず、現在の最大 option_id から続けて、壊れた 0 の行すべてに新しい一意の番号を割り当てます:
SET @next := (SELECT MAX(option_id) FROM wp_options);
UPDATE wp_options
SET option_id = (@next := @next + 1)
WHERE option_id = 0;
次に、すべての値が一意になったので、プライマリキーを追加します:
ALTER TABLE wp_options ADD PRIMARY KEY (option_id);
最後に、自動インクリメントを復元して、WordPress が再び新しいオプションに自動的に番号を付けられるようにします:
ALTER TABLE wp_options MODIFY option_id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT;
これらのステートメントの公式な構文は、MySQL マニュアルの ALTER TABLE の項に記載されています。wp_options の列の正規の定義については、WordPress データベースの説明に、WordPress コアが期待する正確な列の型が一覧されています。
修正を検証する
テーブルを信頼する前に、修復が維持されていることを確認してください:
SHOW CREATE TABLE wp_options;
出力には今度は PRIMARY KEY (option_id) が含まれ、option_id 列に AUTO_INCREMENT が表示されるはずです。最終チェックとして、使い捨てのオプションを挿入して削除するか、単に WordPress で設定を保存し、新しい行が別の 0 ではなく一意でインクリメントする option_id を受け取ることを確認します。
キーが元に戻れば、以前失敗した移行や Staging への PUSH を実行できます。それでも、修復されたテーブルを含む復旧ポイントを確保するため、PUSH の前に新しい Backup を取ってください。
ALTER TABLE が失敗した場合の対処法
ほとんどのインストールはハッピーパスでカバーできますが、いくつかの環境では追加の対応が必要です。次を順番に進めてください:
Duplicate entry '0' for key 'PRIMARY'。 すべての重複が振り直されたわけではありません。診断セクションの重複カウントのクエリを再実行し、残りの行を振り直してから、キーを再度追加します。これが、ALTER TABLEのステップが実行を拒否する最も一般的な理由です。- 大きなテーブルでのロック待ちタイムアウト。
ALTER TABLEはテーブルを書き換え、実行中はロックを保持します。大きなwp_optionsテーブルや、混雑した本番サーバーでは、ステートメントがタイムアウトすることがあります。トラフィックの少ない時間帯に、または Staging のクローンで修復を実行するか、ホストが提供していればpt-online-schema-changeなどのオンラインスキーマ変更ツールを使用してください。 - InnoDB ではなく MyISAM。 手順は両方のエンジンで機能しますが、WordPress は InnoDB で最も良く動作します。
SHOW CREATE TABLE wp_optionsがENGINE=MyISAMと報告する場合は、キーを設定した後にALTER TABLE wp_options ENGINE=InnoDBで変換することを検討してください。変換もテーブルを書き換えるため、まず Backup を取ってください。 - ホスティングがスキーマ変更をブロックする。 一部のマネージドホストは、直接の DDL ステートメントを制限したり、
ALTER権限のないユーザーでデータベースを実行したりします。ステートメントが権限エラーで失敗する場合は、ホストに 3 つのステートメントを代わりに実行してもらうか、一時的に権限を付与してもらうよう依頼してください。
ALTER TABLE の失敗は、ほとんどの場合この 4 つのケースのいずれかです。サーバーログで根本的な SQL エラーを追跡している読者は、WordPress のデバッグ出力にもそれが現れているのを見つけられるかもしれません。WordPress データベースのテーブルの問題を見つける方法についてのガイドで、そのロギングを有効にする方法を説明しています。
なぜこれが移行と PUSH にとって重要なのか
プライマリキーの欠落は、サイトの移動が行き詰まる比較的目立たない理由の 1 つです。Staging から本番への PUSH がタイムアウトしたり転送途中で中断したりする場合、特にシリアライズされたオプション値が関係し、行数が多いときは、wp_options テーブルが第一の容疑者です。ホストを変更するときも同様です: 移動後に siteurl やリダイレクトループと格闘している読者は、私たちの wp_options 内の siteurl の移行ガイドで取り上げているとおり、古いサーバーから壊れたプライマリキーを引きずっている可能性のある、まさにその対象です。先にキーを修正することで、移行の失敗という一連の問題が始まる前に取り除けます。