web-dev-qa-db-ja.com

MySQLの一貫した非ロック読み取りとINSERT ... SELECT

したがって、MySQL 5.5のドキュメントを読んだり、同僚と行ったいくつかの実験から、次のことが当てはまることがわかります。

  1. InnoDBテーブルでは、単純なSELECTステートメント(FOR UPDATEまたはLOCK IN SHARE MODEを使用しないもの)は、SELECTステートメントが読み取るテーブルの行ロックを取得しません。これは、すべてのトランザクション分離レベルに当てはまります。
  2. ただし、トランザクション分離レベルがREPEATABLE READ以上の場合、INSERT ... SELECTまたはCREATE TABLE AS SELECTステートメントは、が読み取るテーブルに行ロックを設定しますから。

出典:

私がこれを正しく理解している場合(そして、理解していない場合は修正します)、この違いに戸惑います。トランザクション分離レベルが同じである場合に、テーブルの読み取りでロック行が必要になるケースがあるのはなぜですか?その理由を知りたいのですが。

2
Luis Casillas

MySQLドキュメント から

読み取りのタイプは、INSERT INTO ... SELECT、UPDATE ...(SELECT)、およびCREATE TABLE ... SELECTなどのFOR UPDATEまたはLOCK IN SHARE MODEを指定しない句のselectによって異なります。

デフォルトでは、InnoDBはより強力なロックを使用し、SELECT部分​​はREAD COMMITTEDのように動作します。同じトランザクション内でも、一貫した読み取りごとに、独自の新しいスナップショットを設定して読み取ります。

このような場合に一貫した読み取りを使用するには、innodb_locks_unsafe_for_binlogオプションを有効にし、トランザクションの分離レベルをREAD UNCOMMITTED、READ COMMITTED、またはREPEATABLE READ(つまり、SERIALIZABLE以外のもの)に設定します。この場合、選択したテーブルから読み取られた行にロックは設定されません。

明らかに、読み取りを行うだけの場合は、より強力なロックは必要ありません。 INSERT ... SELECTまたはCREATE TABLE ... SELECTを使用してテーブルにデータをコピーする画像。 SELECTは、テーブルをロードするための凍結されたスナップショットである必要があります。移動ターゲットの場合、トランザクション内でトランザクションが必要になります。 transaction within a transactionの動作が必要な場合は、 [〜#〜] savepoint [〜#〜] を使用してスクリプトを作成する必要があります。それ以外の場合、より強力なロックにより、アトミックINSERTの一貫したSELECTが可能になります。

単純なSELECTを実行すると、DBセッションは、他のトランザクションを信頼して、データのビューで smoke-and-mirrors を再生できなくなります。その信頼に違反する必要がある場合、データが実際に変化しているときにデータが安定していると考えてSELECTのみを実行しているDBセッションを欺くのではなく、作業を実行できるすべての行を丁寧にロックします。

どの 分離レベル を選択しても、単純なSELECTが維持されるほど細かいものはありません。 SELECT ... FOR UPDATEおよびSELECT ... FROM ... LOCK IN SHARE MODE が発明されたのはそのためです。そのため、ポライトレスがオプションでない場合は、そのように細かくすることができます。

私はこれについて前に書きました: selectステートメントをブロックさせるにはどうすればよいですか?

1
RolandoMySQLDBA