私はDjango管理者の検索がなぜ遅いのか調べてみました(here参照)。さらに掘り下げてみると、MySQL(5.1、InnoDBテーブル)のパフォーマンスはあるクエリから別のものへと大きく変わることがわかりました。例えば:I場合なぜMySQL(InnoDB)のパフォーマンスには多くのバリエーションがありますか?
SELECT DISTINCT `donnees_artiste`.`id`
FROM `donnees_artiste`
LEFT OUTER JOIN `donnees_artiste_evenements`
ON (`donnees_artiste`.`id` = `donnees_artiste_evenements`.`artiste_id`)
LEFT OUTER JOIN `donnees_evenement`
ON (`donnees_artiste_evenements`.`evenement_id` = `donnees_evenement`.`id`)
LEFT OUTER JOIN `donnees_artiste_evenements` T4
ON (`donnees_artiste`.`id` = T4.`artiste_id`)
LEFT OUTER JOIN `donnees_evenement` T5
ON (T4.`evenement_id` = T5.`id`)
LEFT OUTER JOIN `donnees_artiste_evenements` T6
ON (`donnees_artiste`.`id` = T6.`artiste_id`)
LEFT OUTER JOIN `donnees_evenement` T7
ON (T6.`evenement_id` = T7.`id`)
WHERE (
(`donnees_artiste`.`nom` LIKE '%c%'
OR `donnees_artiste`.`prenom` LIKE '%c%'
OR `donnees_evenement`.`cote` LIKE '%c%'
OR `donnees_evenement`.`titre` LIKE '%c%')
AND (`donnees_artiste`.`nom` LIKE '%d%'
OR `donnees_artiste`.`prenom` LIKE '%d%'
OR T5.`cote` LIKE '%d%'
OR T5.`titre` LIKE '%d%')
AND (`donnees_artiste`.`nom` LIKE '%e%'
OR `donnees_artiste`.`prenom` LIKE '%e%'
OR T7.`cote` LIKE '%e%'
OR T7.`titre` LIKE '%e%')
);
:
このクエリで89ミリ秒を取得し、3093行を返しジャンゴによって生成された(4分野での 'C'、 'D' と 'E'、関連の2を探して) 'e'を 'k'で置き換えると、ほとんど同じクエリですが、8720ミリ秒(100倍の増加)を返して931行を返します。
これらのクエリの両方が同じEXPLAIN
を与えるので、そこに手掛かりはありません。私は最初のクエリにCOUNT
をすれば
ID SELECT_TYPE TABLE TYPE POSSIBLE_KEYS KEY KEY_LEN REF ROWS EXTRA
1 SIMPLE donnees_artiste ALL None None None None 4368 Using temporary; Using filesort
1 SIMPLE donnees_artiste_evenements ref artiste_id,donnees_artiste_evenements_eb99df11 artiste_id 4 mmac.donnees_artiste.id 1 Using index; Distinct
1 SIMPLE donnees_evenement eq_ref PRIMARY,donnees_evenements_id_index PRIMARY 4 mmac.donnees_artiste_evenements.evenement_id 1 Using where; Distinct
1 SIMPLE T4 ref artiste_id,donnees_artiste_evenements_eb99df11 artiste_id 4 mmac.donnees_artiste.id 1 Using index; Distinct
1 SIMPLE T5 eq_ref PRIMARY,donnees_evenements_id_index PRIMARY 4 mmac.T4.evenement_id 1 Using where; Distinct
1 SIMPLE T6 ref artiste_id,donnees_artiste_evenements_eb99df11 artiste_id 4 mmac.donnees_artiste.id 1 Using index; Distinct
1 SIMPLE T7 eq_ref PRIMARY,donnees_evenements_id_index PRIMARY 4 mmac.T6.evenement_id 1 Using where; Distinct
また、それは11200ミリ秒を取ります。
SELECT COUNT(DISTINCT `donnees_artiste`.`id`)
FROM `donnees_artiste`
LEFT OUTER JOIN `donnees_artiste_evenements`
ON (`donnees_artiste`.`id` = `donnees_artiste_evenements`.`artiste_id`)
LEFT OUTER JOIN `donnees_evenement`
ON (`donnees_artiste_evenements`.`evenement_id` = `donnees_evenement`.`id`)
LEFT OUTER JOIN `donnees_artiste_evenements` T4
ON (`donnees_artiste`.`id` = T4.`artiste_id`)
LEFT OUTER JOIN `donnees_evenement` T5
ON (T4.`evenement_id` = T5.`id`)
LEFT OUTER JOIN `donnees_artiste_evenements` T6
ON (`donnees_artiste`.`id` = T6.`artiste_id`)
LEFT OUTER JOIN `donnees_evenement` T7
ON (T6.`evenement_id` = T7.`id`)
WHERE (
(`donnees_artiste`.`nom` LIKE '%c%'
OR `donnees_artiste`.`prenom` LIKE '%c%'
OR `donnees_evenement`.`cote` LIKE '%c%'
OR `donnees_evenement`.`titre` LIKE '%c%')
AND (`donnees_artiste`.`nom` LIKE '%d%'
OR `donnees_artiste`.`prenom` LIKE '%d%'
OR T5.`cote` LIKE '%d%'
OR T5.`titre` LIKE '%d%')
AND (`donnees_artiste`.`nom` LIKE '%e%'
OR `donnees_artiste`.`prenom` LIKE '%e%'
OR T7.`cote` LIKE '%e%'
OR T7.`titre` LIKE '%e%')
);
My innodb_buffer_pool_size
が高く設定されています。私はすべての関連フィールドとプライマリキーのインデックスを持っており、私はすでにテーブルを最適化しました。
なぜ、最初のクエリが非常に高速で、2つのクエリが非常に遅いのですか?これらの3つのクエリは例に過ぎません。多くの時間私はちょうどクエリから1文字を変更または削除しており、クエリ時間に大きな違いをもたらしました。しかし、私はどんなパターンも見ることができません。
UPDATE
間違いなく、Djangoはこれらのクエリを生成する方法から来るパフォーマンスの問題。これらのすべての冗長性は、一緒に接続されてパフォーマンスを低下させます。現時点では、Django SQLジェネレータのバグか、検索フィールド用のクエリの作成方法や、Django開発者が期待したとおりに動作するかどうかのバグかどうかは、私には分かりません。私はまだ調査中ですが、Djangoの動作に少なくとも1つの奇妙なことがあります...
このクエリを実行すると(必ずしも2番目のものと同じではないが遠くない)結果がかなり速くなります(161ミリ秒、キャッシュなし):
SELECT DISTINCT `donnees_artiste`.`id`
FROM `donnees_artiste`
LEFT OUTER JOIN `donnees_artiste_evenements`
ON (`donnees_artiste`.`id` = `donnees_artiste_evenements`.`artiste_id`)
LEFT OUTER JOIN `donnees_evenement`
ON (`donnees_artiste_evenements`.`evenement_id` = `donnees_evenement`.`id`)
WHERE (
(`donnees_artiste`.`nom` LIKE '%c%'
OR `donnees_artiste`.`prenom` LIKE '%c%'
OR `donnees_evenement`.`cote` LIKE '%c%'
OR `donnees_evenement`.`titre` LIKE '%c%')
AND (`donnees_artiste`.`nom` LIKE '%d%'
OR `donnees_artiste`.`prenom` LIKE '%d%'
OR `donnees_evenement`.`cote` LIKE '%d%'
OR `donnees_evenement`.`titre` LIKE '%d%')
AND (`donnees_artiste`.`nom` LIKE '%k%'
OR `donnees_artiste`.`prenom` LIKE '%k%'
OR `donnees_evenement`.`cote` LIKE '%k%'
OR `donnees_evenement`.`titre` LIKE '%k%')
);
SECOND UPDATE
が最後にそれはジャンゴのバグではありません、私はそれが必要な動作だと確信しています。アイデアは、マルチターム検索では、次のタームの検索は前のタームでサブセットのリターンで行われるため、関連フィールドではすべてのタームが同じ行にある必要はありません一致。このために、DBは各サブセットを持つ一時テーブルを作成してスキャンする必要があります。これは、最初の用語がほんの数行に一致し、一時テーブルが小さくなり、次の用語の検索が高速になる(なぜなら、それらは小さなテーブル上で実行されるため)、バリエーションが多い理由を説明します。 2つのクエリの違いは微妙ですが、Djangoクエリは一般的により多くの一致を返すことができます。タイプの
速い遅い - それは速く言葉の前で起こる文字である必要があり、私はそれが唯一の限りをスキャン想像必要に応じて言葉にする。それらの中文字 'LIKE'コマンドはほとんど効率的ではありません。 – Orbling
あなたの言葉の先頭に現れる手紙の権利。 'newtover'への私のコメントを見てください。それらの中間文字のLIKEコマンドについては、テキスト内の任意の文字列を検索したいと思っていません。 – Etienne
InnoDBはそのようなテキストフィールドを読むためのセットアップではありません。私が必死に行う必要がある場合、私は通常、MyISAMテーブルにデータをシャドーし、 'MATCH()'で[FULLTEXT'インデックスを使う](http://dev.mysql.com/doc/refman/5.1/ en/fulltext-search.html)。それは通常4文字の単語で停止するので、それは単一の文字には良いことではありませんが。それを変更するためのサーバー全体の設定は、非効率的です。 – Orbling