web-dev-qa-db-ja.com

MySQLは、主キーを使用してUPDATEで範囲と場所を使用します

主キーを使用してMySQLでこれらの単純なSELECTおよびUPDATE要求があり、テーブルには約1,300万行があります。

両方でEXPLAINを実行すると、UPDATEの方が主キーを同じように使用せず、遅いクエリログで遅いと報告されていることに気付きました。

  • タイプは、UPDATEの場合は「範囲」、SELECTの場合はconstです。
  • 追加は、UPDATEの場合は「usingwhere」、SELECTの場合は「NULL」です。

データは次のとおりです。

enter image description here

enter image description here

ご協力ありがとうございました

1
syl.fabre

したがって、クエリオプティマイザのソースコードで範囲を出力する理由を確認する必要がありますが、書き込みの場合、EXPLAINを単純化/制限するために限られた数の書き込みメソッドを使用するだけだと思います。両方のクエリの実際の低行レベルの操作を見ると、SELECT

MariaDB [db]> flush status; SELECT `BuyPacker_Email`.`emailOpen` = 1567007592 FROM `BuyPacker_Email` WHERE `BuyPacker_Email`.`emailId` = 17040352; SHOW STATUS like 'Hand%';
Query OK, 0 rows affected (0.000 sec)
1 row in set (0.000 sec)

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 0     |
| Handler_icp_attempts       | 0     |
| Handler_icp_match          | 0     |
| Handler_mrr_init           | 0     |
| Handler_mrr_key_refills    | 0     |
| Handler_mrr_rowid_refills  | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 0     |
| Handler_read_key           | 1     | <----
| Handler_read_last          | 0     |
| Handler_read_next          | 0     |
| Handler_read_prev          | 0     |
| Handler_read_retry         | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_deleted   | 0     |
| Handler_read_rnd_next      | 0     |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_tmp_delete         | 0     |
| Handler_tmp_update         | 0     |
| Handler_tmp_write          | 0     |
| Handler_update             | 0     |
| Handler_write              | 0     |
+----------------------------+-------+
27 rows in set (0.001 sec)

...単一の行の読み取りとインデックス付けを行います。そして更新のために:

MariaDB [db]> FLUSH STATUS; UPDATE `BuyPacker_Email` SET `BuyPacker_Email`.`emailOpen` = 1567007592 WHERE `BuyPacker_Email`.`emailId` = 17040352; SHOW STATUS like 'Hand%';
Query OK, 0 rows affected (0.000 sec)

Query OK, 0 rows affected (0.000 sec)
Rows matched: 1  Changed: 0  Warnings: 0

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 2     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 0     |
| Handler_icp_attempts       | 0     |
| Handler_icp_match          | 0     |
| Handler_mrr_init           | 0     |
| Handler_mrr_key_refills    | 0     |
| Handler_mrr_rowid_refills  | 0     |
| Handler_prepare            | 2     |
| Handler_read_first         | 0     |
| Handler_read_key           | 1     | <-----
| Handler_read_last          | 0     |
| Handler_read_next          | 0     |
| Handler_read_prev          | 0     |
| Handler_read_retry         | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_deleted   | 0     |
| Handler_read_rnd_next      | 0     |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_tmp_delete         | 0     |
| Handler_tmp_update         | 0     |
| Handler_tmp_write          | 0     |
| Handler_update             | 1     |  <----
| Handler_write              | 0     |
+----------------------------+-------+
27 rows in set (0.000 sec)

...まったく同じ読み取り戦略+必要な書き込みを使用してレコードを更新します。

したがって、必要以上に多くのレコードを読み取るというオーバーヘッドや、より高価な読み取りプランに関する違いはありません。それがEXPLAINの単純化であるか、それとも書き込みクエリによる制限であるかどうか。または、書き込みがどのように機能するかを示し、実際のパフォーマンスへの影響を示すため、実際の違いを示します。 実装の詳細 -に入る必要がありますが、ほとんどの場合、行の列に「1」と表示されている限り、クエリに問題はありません。大まかに言えば、1行の範囲はconstアクセスとほぼ同等であるはずです。

1
jynus