これに似たテーブルがあります
mysql> SHOW CREATE TABLE my_requests\G *************************** 1.行** ************************* テーブル:my_requests テーブルの作成:CREATE TABLE `my_requests`( `rq_id` bigint(20)NOT NULL、 ` t_id` bigint(20)NOT NULL、 `u_id` bigint(20)DEFAULT NULL、 ` rq_date` datetime DEFAULT NULL、 `rq_type` tinyint(4)DEFAULT '1'、 ` rq_creationdate` datetime NOT NULL、 `rq_modifydate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP、 `rq_ttotal` mediumint(8)unsigned DEFAULT '0'、 KEY` index_rqcd`( `t_id`、` rq_date`)、 KEY `idx_rq_u`(` u_id`)、 KEY `idx_rq_id`(` rq_id`) )ENGINE = InnoDB DEFAULT CHARSET = utf8 /*!50100 PARTITION BY LIST(to_days(rq_date)) SUBPARTITION BY HASH(t_id) SUBPARTITIONS 10 (PARTITION p736417 VALUES IN(736417)ENGINE = InnoDB、 PARTITION p736419 VALUES IN(736419)ENGINE = InnoDB、 パーティションp736430の値S IN(736430)ENGINE = InnoDB、 PARTITION p736439 VALUES IN(736439)ENGINE = InnoDB、 PARTITION p736443 VALUES IN(736443)ENGINE = InnoDB、 PARTITION p736444 VALUES IN (736444)ENGINE = InnoDB、 PARTITION p736445 VALUES IN(736445)ENGINE = InnoDB、 PARTITION p736446 VALUES IN(736446)ENGINE = InnoDB、 PARTITION p736447 VALUES IN(736447) )ENGINE = InnoDB、 PARTITION p736448 VALUES IN(736448)ENGINE = InnoDB、 PARTITION p736449 VALUES IN(736449)ENGINE = InnoDB、 PARTITION p736450 VALUES IN(736450)ENGINE = InnoDB、 PARTITION p736451 VALUES IN(736451)エンジン= InnoDB、 PARTITION p736452 VALUES IN(736452)エンジン= InnoDB、 PARTITION p736453 VALUES IN(736453)エンジン= InnoDB 、 PARTITION p736454 VALUES IN(736454)ENGINE = InnoDB、 PARTITION p736455 VALUES IN(736455)ENGINE = InnoDB、 PARTITION p736456 VALUES IN(736456)ENGINE = InnoDB、 PARTITION p736457 VALUES IN(73 6457)ENGINE = InnoDB、 PARTITION p736458 VALUES IN(736458)ENGINE = InnoDB、 PARTITION p736459 VALUES IN(736459)ENGINE = InnoDB、 PARTITION p736460 VALUES IN(736460) ENGINE = InnoDB、 PARTITION p736461 VALUES IN(736461)ENGINE = InnoDB、 PARTITION p736462 VALUES IN(736462)ENGINE = InnoDB、 PARTITION p736463 VALUES IN(736463)ENGINE = InnoDB、 PARTITION p736464 VALUES IN(736464)ENGINE = InnoDB、 PARTITION p736465 VALUES IN(736465)ENGINE = InnoDB、 PARTITION p736466 VALUES IN(736466)ENGINE = InnoDB、 PARTITION p736467 VALUES IN(736467)ENGINE = InnoDB、 PARTITION p736468 VALUES IN(736468)ENGINE = InnoDB、 PARTITION p736469 VALUES IN(736469)ENGINE = InnoDB)*/
日ごとのパーティションを使用すると、テーブルは巨大で数億のレジスターがあり、-最終日のデータを選択しようとしています=フルスキャンを回避し、最後のパーティションのみにアクセスします。
しかし、説明すると、インデックスは使用されません。
EXPLAIN SELECT * FROM my_requests USE INDEX(index_rqcd) WHERE t_id <> -1 AND rq_date = DATE_SUB(now()、INTERVAL 1 DAY); + ---- + ------------- + ------------- + ------ + -------------- -+ ------ + --------- + ------ + --------- + ------------- + | id | select_type |テーブル|タイプ|可能性のあるキー|キー| key_len | ref |行|追加| + ---- + ------------- + ------------- + ------ +- ------------- + ------ + --------- + ------ + --------- +- ----------- + | 1 |シンプル| my_requests |すべて| index_rqcd | NULL | NULL | NULL | 4020468 |使用場所| + ---- + ------------- + ------------- + ------ +- -------------- + ------ + --------- + ------ + --------- +- ------------ +
編集:EXPLAIN PARTITIONS
は、クエリがパーティションの一部にのみ影響することを示していますが、インデックスが使用されない理由がまだわかりません。
mysql> EXPLAIN PARTITIONS SELECT * FROM my_requests WHERE t_id <> -1 AND rq_date = DATE_SUB(now()、INTERVAL 1 DAY)\ G ****** ********************* 1.行************************** * id:1 select_type:SIMPLE table:my_requests partitions:p736467_p736467sp0、p736467_p736467sp1、p736467_p736467sp2、p736467_p736467sp7,467p467p736_p736_4673736p467_p736_4673736_p736_p736_p736_p736_p736_p736_p736_p736_467736 p736467_p736467sp9 タイプ:ALL possible_keys:index_rqcd キー:NULL key_len:NULL ref:NULL rows:4064737 Extra:where 1行をセットで使用(0.06秒)
このインデックスがそのクエリに使用されない理由を理解するのに役立ちますか?
ここにいくつかの問題があります:
まず、jkavalikがOPのコメントで述べているように、インデックスの列の順序が重要です。基本的に、index_rqcd
をrq_date
のフィルタリングに使用する場合、t_id
を使用してrq_date
を「表示」してフィルタリングする必要があります。通常、クエリに対してインデックスで実行できる範囲スキャンは1つだけであり、それは使用されるインデックスの最後の部分でなければならないため、オプティマイザはこのインデックスの使用を正しくスキップします。インデックスで、次にテーブルまたはこの場合はパーティションでフルスキャンします。テーブルにrq_date
で始まるインデックスがある場合、そのインデックスが使用される可能性があります。
次に、パーティションを使用するときに注意する必要があるのは、MySQLにはパーティションテーブルのグローバルインデックスがないということです。つまり、各パーティションには独自のインデックスがあるため、そのパーティション内でのみ使用できます。オプティマイザは、クエリがクエリとテーブル定義(パーティションプルーニングと呼ばれる最適化)に基づいてパーティションp736467
を使用するだけでよいことを知っているので、クエリを実行します。したがって、オプティマイザはパーティションp736467
のみを使用しているので、index_rqcd
の使用を検討できますが、それでも最初の問題の影響を受け、その使用はインデックスのフルスキャンにつながるため、データのフルスキャンを実行します。タイプのEXPLAIN
はALL
を示していますが、パーティションのプルーニングのため、テーブル全体ではなく、p736467
パーティションのデータのみをスキャンしています。 rq_date
で始まるインデックスを追加しても、パーティションが存在する日のすべての行を取得する場合は使用されません。ただし、指定したクエリでは、1日前から2日目までの行のみが返され、何をしたいかを説明するときに1日が返されるわけではありません。 1日ではなく特定の時間の行を取得したい場合は、rq_date
で始まるインデックスが便利です。
おそらくここで最も重要なことは、jkavalikが投稿したリンクで述べられているように、正当な理由がない限りパーティションを使用すべきではないということです。時間範囲はパーティションの有効な使用法ですが、通常、時系列データのスライディングウィンドウで使用する場合のみです。毎日除去される7日間のログメッセージ。一般に、すべてのクエリでパーティションプルーニングを使用できない限り、すべてのパーティションにアクセスする必要があるため、パフォーマンスが低下します。特定の日付の行についてこのテーブルを常にクエリし、他のいくつかのインデックス付き列の範囲でフィルタリングする場合は、パーティションが役立つ場合があります。多くの場合、パーティションは適切な方法ではありません。 veryサブパーティションを使用する十分な理由がない限り、ほとんどすべてのクエリにオーバーヘッドが追加されるだけです。
私の提案は、ほとんどのクエリがrq_date
の範囲に基づいていると仮定して、パーティションを使用せず、rq_date
で始まるインデックスを追加することです。
また、InnoDBを使用する場合は、常に主キーを定義する必要があります。保存しているデータについてはわかりませんが、rq_id
は一意であり、適切な候補のようです。
そのパーティショニングに関する3つの問題:
BY HASH
_は無用です。SUBPARTITIONing
は役に立たない。PARTITION BY RANGE(TO_DAYS(rq_date))
のみを使用します。大きなメリットは「スライディングウィンドウ」にあります。
my partitioning blog のその他のコメント。
行の何パーセントに_t_id <> -1
_がありますか?約20%を超える場合、_PRIMARY KEY
_が_t_id
_で始まる場合を除き、インデックスは使用されません。また、_t_id <> -1
_を_t_id > -1
_に変更できますか?これは、オプティマイザが「範囲」テストを実行するのに役立つ場合があります。 _<>
_は最適化が困難です。
InnoDBは本当に_PRIMARY KEY
_を明示的に指定することを望んでいます。列(または列の組み合わせ)のいずれかはすでに「一意」ですか?その場合、それは_PRIMARY KEY
_である必要があります。ただし、最後に_rq_date
_を追加する必要があります。 _rq_id
_についての言及があったので、
_PRIMARY KEY(t_id, rq_id_, rq_date)
_
それは少し長くなっているので、多分それは最善ではありません。列をよりよく理解する必要があります。