2

私のテーブル構造は以下のようなものです:

CREATE TABLE test (
    id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,

    field_1 VARCHAR(60) NOT NULL,
    field_2 INT(10) UNSIGNED NULL,
    field_3 INT(10) UNSIGNED NULL,
    field_4 INT(10) UNSIGNED NULL,
    field_5 CHAR(2) NULL,
    field_6 INT(10) UNSIGNED NOT NULL,

    rank TINYINT(2) NOT NULL DEFAULT '0',   
    status TINYINT(3) NOT NULL DEFAULT '0',

    PRIMARY KEY (id),
    INDEX (status)

) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE = MyISAM;

上記の表では、フィールドrankstatusはそれぞれ 0 ~ 9 と 0 ~ 4 の間の整数値を持ちます。

現在、テーブルには約 950K のデータがあり、クエリを可能な限り最適化しようとしています。

基本的に、 field で降順の where 句を使用してフィールドを選択する必要がありますrank

たとえば、以下にいくつかの SQL クエリを示します。

SELECT field_1, field_2, field_3 FROM test WHERE field_1 = 'data1' && status IN ('0', '1', '2') ORDER BY rank DESC LIMIT 0, 20;
SELECT field_1, field_2, field_3 FROM test WHERE field_2 = '5' && status IN ('1', '2') ORDER BY rank DESC LIMIT 0, 20;
SELECT field_1, field_2, field_3 FROM test WHERE field_5 = 'US' && status IN ('0', '2') ORDER BY rank DESC LIMIT 0, 20;

上記のクエリORDER BY rank DESCは非常に重要です。したがって、単一列または複数列にインデックスを追加する必要があるかどうかはかなり混乱しています。

誰かが私に最善の解決策を提案してくれませんか。

4

1 に答える 1

2

あなたの主な問題は、status列に最大 4 つの異なる値がある 95 万行を超えることです。BTREE インデックスでは、これを処理するのは非常に面倒です。

上記の 3 つのクエリに使用するより効果的なインデックスは、おそらく次のとおりです。

INDEX forQuery1 ( field_1 , status , rank ) USING BTREE,
INDEX forQuery2 ( field_2 , status , rank ) USING BTREE,
INDEX forQuery3 ( field_5 , status , rank ) USING BTREE,

2 番目のクエリは特にメリットがあることがわかりますが、データセットのサイズに対してデータの分散が非常に低く、おそらく MySQL がテーブル スキャンにフォールバックするという問題が引き続き発生しますが、EXPLAIN はおそらく、その影響を軽減するために LIMIT を表示します。言及されたインデックスは、どの行を返すかを決定するのに適しているはずです。

MySQL がインデックスを使用する方法の詳細については、13.1.13 を参照してください。CREATE INDEX 構文、特にB ツリー インデックスの特性に関するセクションと以下の抜粋

テーブルに複数列のインデックスがある場合、オプティマイザーはインデックスの左端のプレフィックスを使用して行を検索できます。たとえば、(col1、col2、col3) に 3 列のインデックスがある場合、(col1)、(col1、col2)、および (col1、col2、col3) にインデックス付き検索機能があります。

列がインデックスの左端のプレフィックスを形成しない場合、MySQL はインデックスを使用できません。次に示す SELECT ステートメントがあるとします。

インデックスが利用可能であっても、MySQL がインデックスを使用しないことがあります。これが発生する状況の 1 つは、インデックスを使用すると MySQL がテーブル内の行の大部分にアクセスする必要があるとオプティマイザが推定した場合です。(この場合、必要なシークが少ないため、テーブル スキャンははるかに高速になる可能性があります。) ただし、そのようなクエリで LIMIT を使用して一部の行のみを取得する場合、MySQL はとにかくインデックスを使用します。結果で返される数行。

追加の注意として、数値データ型を引用する必要はなく、field_2 = 5 && status IN ( 1 , 2 )有効です(実際、数値として指定する代わりに整数データ型を引用したために、過去に奇妙な問題が発生しました)

于 2013-06-12T23:49:28.793 に答える