5

次のようなクエリの例があります。

SELECT 
    rest.name, rest.shortname
FROM
    restaurant AS rest
    INNER JOIN specials ON rest.id=specials.restaurantid
WHERE
    specials.dateend >= CURDATE()
AND
    rest.state='VIC'
AND
    rest.status = 1
AND
    specials.status = 1
ORDER BY
    rest.name ASC;

以下の2つのインデックスについて疑問に思っていますが、どちらがレストランのテーブルに最適でしょうか。

id,state,status,name
state,status,name

結合で使用される列を含める必要があるかどうかわからない場合は、

面白いことに、私はテスト用に両方のタイプを作成しましたが、どちらの場合もMySQLはプライマリインデックスを選択します。これはちょうどidです。何故ですか?

出力の説明:

1,'SIMPLE','specials','index','NewIndex1\,NewIndex2\,NewIndex3\,NewIndex4','NewIndex4','11',\N,82,'Using where; Using index; Using temporary; Using filesort',
1,'SIMPLE','rest','eq_ref','PRIMARY\,search\,status\,state\,NewIndex1\,NewIndex2\,id-suburb\,NewIndex3\,id-status-name','PRIMARY','4','db_name.specials.restaurantid',1,'Using where'

現時点では行が少ないので、おそらくそれがPRIMARYを選択している理由です!?

4

1 に答える 1

2

最適なパフォーマンスを得るには、少なくとも2つのインデックスが必要です。

最も重要なインデックスは、外部キーのインデックスです。

CREATE INDEX specials_rest_fk ON specials(restaurantid);

これがないと、条件にrest一致するすべての行で全表スキャンが必要になるため、クエリのパフォーマンスが低下します。WHEREspecials

次に定義するインデックスは、rest特定の条件で最も少ない行を検索するのに役立つインデックスです。restこれまでに使用されるインデックスは1つだけなので、そのインデックスでできるだけ少ない行を検索するようにします。

私の推測、状態、ステータス:

CREATE INDEX rest_index_1 on rest(state, status);

idは一意であるため、(id、...)のインデックスの提案は無意味です。列を追加しても効果はありません。実際、インデックスエントリが大きくなり、次のようになるため、列を追加するとパフォーマンスが低下します。読み取られるI/Oページあたりのエントリが少なくなります。

ただし、クエリをより適切に作成することでパフォーマンスを向上させることもできます。スペシャルの条件を結合ON条件に移動すると、結合条件は結合が行われるときに評価されますが、条件はすべての結合行で評価されるため、パフォーマンスが大幅に向上します。つまり、一時的な結果セットは、WHERE句ははるかに大きいため、遅くなります。

クエリを次のように変更します。

SELECT rest.name, rest.shortname
FROM restaurant AS rest
INNER JOIN specials 
    ON rest.id=specials.restaurantid
    AND specials.dateend >= CURDATE()
    AND specials.status = 1
WHERE rest.state='VIC'
AND rest.status = 1
ORDER BY rest.name;

スペシャルの条件がどのようにON条項に含まれているかに注意してください。

于 2012-12-16T17:26:11.650 に答える