私はワードプレスのインストールをしており、私はすべての投稿にこのクエリが必要です。
select post_id, meta_key from wp_postmeta where meta_key = 'mykey' and meta_value = 'somevalue'
そのテーブルに3Mの行があり、クエリが完了するまでに約6秒かかります。もっと早くなるべきだと思います。テーブルのインデックスを表示すると、それが返されます。
SHOW INDEX FROM wp_postmeta
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
wp_postmeta 0 PRIMARY 1 meta_id A 3437260 NULL NULL BTREE
wp_postmeta 1 post_id 1 post_id A 1718630 NULL NULL BTREE
wp_postmeta 1 meta_key 1 meta_key A 29 191 NULL YES BTREE
説明すると、これが返されます。
explain select post_id, meta_key from wp_postmeta where meta_key = 'mykey' and meta_value = 'somevalue'
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE wp_postmeta ref meta_key meta_key 767 const 597392 Using where
私はmysqlがあまり得意ではないので、それをチェックまたは解決する方法がわかりません。あなたは私に問題がどこにあるかについていくつかの方向性を与えることができますか?
ありがとうございました。
wp_postmeta
には非効率なインデックスがあります。公開されている表(Wikipediaを参照)は
CREATE TABLE wp_postmeta (
meta_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
post_id bigint(20) unsigned NOT NULL DEFAULT '0',
meta_key varchar(255) DEFAULT NULL,
meta_value longtext,
PRIMARY KEY (meta_id),
KEY post_id (post_id),
KEY meta_key (meta_key)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
問題点:
AUTO_INCREMENT
は何の利点もありません。実際、ほとんどのクエリは遅くなります(auto_inc idを見つけるために二次インデックスを調べなければならないので、次に必要な実際のidについてデータを調べる必要があるためです)。AUTO_INCREMENT
は、ディスク上とキャッシュ内の両方で余分な混乱を招きます。PRIMARY KEY(post_id, meta_key)
の方がはるかに優れています - クラスター化され、通常のJOIN
の両方の部分を処理します。BIGINT
はやり過ぎですが、他のテーブルを変更しなければ修正できません。VARCHAR(255)
はMySQL 5.6ではutf8mb4
を伴う問題となる可能性があります。下記の回避策を参照してください。NULL
になるのはいつですか?解決策:
CREATE TABLE wp_postmeta (
post_id BIGINT UNSIGNED NOT NULL,
meta_key VARCHAR(255) NOT NULL,
meta_value LONGTEXT NOT NULL,
PRIMARY KEY(post_id, meta_key),
INDEX(meta_key)
) ENGINE=InnoDB;
典型的な使い方
JOIN wp_postmeta AS m ON p.id = m.post_id
WHERE m.meta_key = '...'
ノート:
PRIMARY KEY
は、目的の行に直接進みます。副次索引では省略せず、複数行でも検索しません。INDEX(meta_key)
はあなたが他にどんなクエリを持っているかに依存して、役に立つかもしれないし、そうでないかもしれません。エラー "max key length is 767"は、MySQL 5.6でCHARACTER SET utf8mb4を使用しようとしたときに発生する可能性があります。エラーを回避するには、次のいずれかを実行します(それぞれに欠点があります)。
潜在的な非互換性
meta_id
はおそらくどこでも使われていません。 (しかしそれを削除するのは危険です)。meta_id
を維持し、ほとんどの利点を得ることができます。PRIMARY KEY(post_id, meta_key, meta_id), INDEX(meta_id), INDEX(meta_key, post_id)
。 (注:PKの最後にmeta_id
を付けることで、post_id + meta_keyが一意でなくなる可能性があります。)BIGINT
から小さなデータ型に変更すると、他のテーブルも変更されます。utf8mb4
VARCHAR(191)
に縮小すると、以前の任意の「255」の制限ではなく、現在の「191」という制限であることをユーザーは理解する必要があります。コメント
私が主張していることのいくつかがWordPressロードマップにあることを願っています。一方、stackoverflowとdba.stackexchangeは、「なぜWPの実行が非常に遅いのですか」と雑然としています。私はここで与えられた修正がそのような苦情タイプの質問でかなり削減するだろうと思います。
互換性の問題があるにもかかわらず、一部のユーザーはutf8mb4に変更していることに注意してください。それから彼らは困っている。私は彼らが抱えているすべてのMySQL問題に対処しようとしました。
リックジェームズmysqlのブログから撮影: ソース
あなたがDBのパフォーマンスを「そのまま」探しているのであれば、postメタテーブルはあなたが探したいものを保存するのに間違った場所です。クエリの記述方法は、その使用例に分類法を使用するほうがはるかに優れています。
しかし、DBを再構築するには「うさぎの穴」を過ぎているのであれば、クエリを高速化するのには役に立たないかもしれませんが、キャッシュソリューションを検討する必要があります。必要に応じてcronを使用してキャッシュを生成すると、ユーザーへの影響はほとんどありません。