2017-09-27 6 views
0

先週私はいくつかの追加のデータベースモニタリングをインストールして、のデータベース負荷の30%がの1つのテーブル(現在は600万行):テスト環境でmdl_grade_items_historyからの最適化

delete FROM mdl_grade_items_history WHERE timemodified < ? 

は、私はいくつかのスキーマ変更を作ってみました:

は、このクエリにEXPLAINを実行し、このクエリが実行されるたびに、全表スキャンが行われていることを示しています。 (非常によく似た)SELECTクエリのEXPLAINをチェック

EXPLAIN DELETE FROM mdl_grade_items_history WHERE timemodified < '1490528405'; 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
| id | select_type | table     | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
| 1 | DELETE  | mdl_grade_items_history | NULL  | ALL | NULL   | NULL | NULL | NULL | 140784 | 100.00 | Using where | 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
1 row in set (0.00 sec) 

は、類似した状況を示しています。

テーブル定義を確認する
EXPLAIN SELECT id FROM mdl_grade_items_history WHERE timemodified < '1490528405'; 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
| id | select_type | table     | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
| 1 | SIMPLE  | mdl_grade_items_history | NULL  | ALL | NULL   | NULL | NULL | NULL | 140784 | 33.33 | Using where | 
+----+-------------+-------------------------+------------+------+---------------+------+---------+------+--------+----------+-------------+ 
1 row in set, 1 warning (0.01 sec) 

、でtimemodified

SHOW INDEX FROM mdl_grade_items_history; 
+-------------------------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| Table     | Non_unique | Key_name    | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | 
+-------------------------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
| mdl_grade_items_history |   0 | PRIMARY     |   1 | id   | A   |  140784 |  NULL | NULL |  | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_act_ix |   1 | action  | A   |   2 |  NULL | NULL |  | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_old_ix |   1 | oldid  | A   |  17170 |  NULL | NULL |  | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_cou_ix |   1 | courseid | A   |  1065 |  NULL | NULL | YES | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_cat_ix |   1 | categoryid | A   |  2300 |  NULL | NULL | YES | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_sca_ix |   1 | scaleid  | A   |   6 |  NULL | NULL | YES | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_out_ix |   1 | outcomeid | A   |   1 |  NULL | NULL | YES | BTREE  |   |    | 
| mdl_grade_items_history |   1 | mdl_graditemhist_log_ix |   1 | loggeduser | A   |   30 |  NULL | NULL | YES | BTREE  |   |    | 
+-------------------------+------------+-------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 
8 rows in set (0.00 sec) 

だから私は(両方CREATE INDEXALTER TABLE .. ADD INDEXを経由して)1を追加しようとしました

CREATE INDEX `mdl_gradeitemhist_tim_ix` ON `mdl_grade_items_history` (`timemodified`); 
ALTER TABLE `mdl_grade_items_history` ADD INDEX `mdl_gradeitemhist_tim_ix` (`timemodified`); 

にインデックスがあるようには思えませんどちらのインスタンスでも、SELECTクエリが影響を受けました(typeの変更に注意してください)

EXPLAIN `SELECT` id FROM mdl_grade_items_history WHERE timemodified < '1490528405'; 
+----+-------------+-------------------------+------------+-------+--------------------------+--------------------------+---------+------+-------+----------+--------------------------+ 
| id | select_type | table     | partitions | type | possible_keys   | key      | key_len | ref | rows | filtered | Extra     | 
+----+-------------+-------------------------+------------+-------+--------------------------+--------------------------+---------+------+-------+----------+--------------------------+ 
| 1 | SIMPLE  | mdl_grade_items_history | NULL  | range | mdl_gradeitemhist_tim_ix | mdl_gradeitemhist_tim_ix | 9  | NULL | 70206 | 100.00 | Using where; Using index | 
+----+-------------+-------------------------+------------+-------+--------------------------+--------------------------+---------+------+-------+----------+--------------------------+ 
1 row in set, 1 warning (0.00 sec) 

ただし、DELETEクエリではありません。

EXPLAIN DELETE FROM mdl_grade_items_history WHERE timemodified < '1490528405'; 
+----+-------------+-------------------------+------------+------+--------------------------+------+---------+------+--------+----------+-------------+ 
| id | select_type | table     | partitions | type | possible_keys   | key | key_len | ref | rows | filtered | Extra  | 
+----+-------------+-------------------------+------------+------+--------------------------+------+---------+------+--------+----------+-------------+ 
| 1 | DELETE  | mdl_grade_items_history | NULL  | ALL | mdl_gradeitemhist_tim_ix | NULL | NULL | NULL | 140412 | 100.00 | Using where | 
+----+-------------+-------------------------+------------+------+--------------------------+------+---------+------+--------+----------+-------------+ 
1 row in set (0.00 sec) 

どうしたのですか?他に何を試すことができますか?

+0

指数はさらににより変更するためのインデックスを引き起こし削除までDELETEが遅くなると思いませんか?あなたの大きなテーブルと他の大きなテーブルとの間には、外部キー関係はありますか?私はそれらも大きな削除を遅くすることができると信じて、それはそれらを削除し、削除し、その場合再作成するために働くかもしれない。またはループを使用して一度にレコードのx個の量を「バッチ」で削除できますか? – Nope

+0

@Fran私の知る限り、外部キーはありません。バッチでDELETEにクエリを変更するのは確かにテーブルの上にあります。 –

答えて

1
  • 低カーディナリティインデックス(action、scaleid、outcomeid)はほとんど使用されません。それらを取り除く。
  • 単一列索引が多数あることは赤いフラグです。 「コンポジット」インデックスのパワーとメリットについて学んでください。
  • テーブルの余分なインデックスは、索引を最終的に更新する必要があるため、INSERTsDELETEsの速度が若干低下します(これは、ここで説明した選択/削除とは関係ありませんが、おそらく他のクエリにも関係します)。
  • インデックス付きの列が変更された場合は、余分なインデックスが遅くなります。UPDATEs
  • CREATE INDEXALTER TABLE ADD INDEXは同じことを行います。あなたはおそらく冗長なインデックスを持っているでしょう。
  • EXPLAINsは、(1)SELECTDELETEが異なるものであり、(2)EXPLAINがあまり洗練されていないために異なります。
  • 多くの行を削除することには多くの労力が必要です。削除された行は、ROLLBACKの場合にハングアップすることに注意してください。 COMMITの後にのみ、実際に行を削除することができます。 (autocommit=ONの場合、暗黙的なCOMMITがあります。)大規模な削除の

ヒント: