MySQLでロックを引き起こさずに選択する方法はありますか?


126

クエリ:

SELECT COUNT(online.account_id) cnt from online;

しかし、オンラインテーブルもイベントによって変更されるため、を実行するとロックが頻繁に表示されますshow processlist

MySQLに、selectステートメントをロックさせない文法はありますか?

また、MySQLスレーブデータベース上にあることを前述したことを忘れていました。

my.cnf:transaction-isolation = READ-UNCOMMITTED スレーブに追加した後、エラーが発生します:

エラー 'バイナリログはできません。メッセージ:InnoDBのトランザクションレベル「READ-UNCOMMITTED」は、クエリのバイナリログモード「STATEMENT」では安全ではありません

それで、これを行う互換性のある方法はありますか?


3
この質問に遭遇し、テーブルのロックで苦労している他の人にとって:mySQLがロックを内部でどのように使用するかは、ストレージエンジンに依存します。以下の@zombatの回答を読んでください。
Simon Forsberg、2012

回答:


169

「MYSQL WITH NOLOCK」というタイトルの記事が見つかりました

https://web.archive.org/web/20100814144042/http://sqldba.org/articles/22-mysql-with-nolock.aspx

MS SQL Serverでは、次のようにします。

SELECT * FROM TABLE_NAME WITH (nolock)

MYSQLに相当するものは

SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ ;

編集

Michael Miorは次のことを提案しました(コメントから)

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
SELECT * FROM TABLE_NAME ;
COMMIT ;

54
除外SESSIONしたいトランザクションレベルを次のトランザクションにのみ適用することをお勧めします。次に、上記の3番目のステートメントをに置き換えCOMMITます。この場合、これは何もしませんが、トランザクションを終了し、デフォルトの分離レベルにリセットするという副作用があります。
Michael Mior

3
ただのメモ、そのリンクは死んでいる... :(
longda

5
申し訳ありませんが、ここではInnoDBとMyISAMの非常に重要な違いについて触れなかったため、この回答に反対票を投じる必要があります。上記の@omgで述べたように、これはInnoDBでは機能しますが、MyISAMテーブルでは機能しません。
Simon Forsberg、2012

4
確かにSELECT中にMyISAMテーブルはREADロックを発行していないこと、不正確である@Craig照会-そこにあるロックは、それらのロックが要求されたすべてのWRITEロックブロック、テーブルロックされているInnoDBテーブルと対向し、実行中のすべての後続の問合せを。元の質問はInnoDBに関するもののようですが、MyISAMにも分離レベルは存在しません- ステートメントの状態のドキュメントSET TRANSACTION「このステートメントは、InnoDBテーブルの操作に使用されるトランザクション分離レベルを設定します。」
syneticon-dj 2013

1
ポイントは認められた。:-)私は本当にMyISAMとInnoDBのロック動作を参照しようとしていました。これらの分離レベルベースのソリューションは、トランザクションではないMyISAMには適用されないため単純なテーブルロックを使用ます。MyISAM UPDATEおよびDELETEはテーブルロックがクリアされるまで待機する必要があるため、後続のSELECTのキューは書き込みリクエストの背後にあり、書き込みが完了するまでブロックされます。MyISAMには「ダーティリード」がなく、ほとんどの書き込みを読み取りと同時に実行する方法がないため、ここで「MyISAMに対応できない」というコメントについて理解することはできません。それは私が得ていたものだと思います。:-)
クレイグ

24

テーブルがInnoDBである場合は、http: //dev.mysql.com/doc/refman/5.1/en/innodb-consistent-read.htmlを参照してください。これは、SELECTに対応する一貫した読み取り(非ロックモード)を使用しますinnodb_locks_unsafe_for_binlogオプションが設定されており、トランザクションの分離レベルがSERIALIZABLEに設定されていない場合は、FOR UPDATEまたはLOCK IN SHARE MODEを指定しないでください。したがって、選択したテーブルから読み取られた行にロックは設定されません。


16

使用する

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

バージョン5.0のドキュメントはこちらです。

バージョン5.1のドキュメントはこちらです。


2
ありがとう、近いと思いますが、この発言にはどのくらいの時間がかかりますか?私はこのプログラムをPHPプログラムで使用します。クエリが終了したら、トランザクションの分離レベルを自動的にリセットするのが最適です
omg

14

MySQLマニュアルのこのページを読むことをお勧めします。テーブルがロックされる方法は、テーブルのタイプによって異なります。

MyISAMは非常に高い読み取り速度を達成するためにテーブルロックを使用しますが、UPDATEステートメントが待機している場合、その後のSELECTSはUPDATEの後ろにキューイングされます。

InnoDBテーブルは行レベルのロックを使用しており、UPDATEの背後でテーブル全体がロックされることはありません。InnoDBに関連する他の種類のロックの問題がありますが、ニーズに合っている場合があります。


1
「SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED」はMyISAMテーブルで機能しますか?
omg

5
MyISAMテーブルは、どのような形式のトランザクションもサポートしていません。トランザクションクエリはMyISAMテーブルで実行されるため、上記のクエリは実行されますが、効果はありません。
zombat 2009年

1
次に、MyISAMの場合にSELECTSがキューに入るのを避けるにはどうすればよいですか?
omg

6
MyISAMの場合にSELECTSのキューイングを回避するにはどうすればよいですか? innodbに切り替えます。MyISAMは、すべてのクエリに対してテーブルレベルのロックを使用します。それが大きな欠点です。
フランクファーマー

2

テーブルのタイプに応じて、ロックの動作は異なりますが、SELECTのカウントも異なります。MyISAMテーブルの場合、単純なSELECT count(*)FROMテーブルはメタデータにアクセスしてレコードカウントをプルするため、テーブルをロックしないでください。Innodbは、レコードをカウントするためにスナップショットのテーブルを取得する必要があるため、さらに時間がかかりますが、ロックが発生することはありません。

少なくとも、concurrent_insertを1(デフォルト)に設定する必要があります。次に、データファイルにテーブルが埋める「ギャップ」がない場合、挿入がファイルに追加され、MyISAMテーブルと同時にSELECTおよびINSERTが発生する可能性があります。レコードを削除すると、データファイルに「ギャップ」ができ、今後の挿入や更新で埋めようとすることに注意してください。

レコードをめったに削除しない場合は、concurrent_insertを2に設定できます。挿入は常にデータファイルの最後に追加されます。その後、選択と挿入は同時に行われますが、削除するレコードの数(すべてのレコードを除く)に関係なく、データファイルが小さくなることはありません。

一番下の行は、テーブルに多くの更新、挿入、選択がある場合、それをInnoDBにする必要があります。ただし、システム内でテーブルタイプを自由に混在させることができます。


0

この参照から:

LOCK TABLESを使用してテーブルロックを明示的に取得する場合、READロックではなくREAD LOCALロックを要求して、テーブルがロックされている間に他のセッションが同時挿入を実行できるようにすることができます。


0

SELECTは通常、InnoDBテーブルで気になるロックを行いません。デフォルトのトランザクション分離レベルは、「ロックしない」を選択することを意味します。

もちろん競合はまだ起こります。


1
私はこの投稿が古いことを知っていますが、この答えは一般的すぎるため、たまにしか当てはまりません。dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.htmlを参照してください。ロック最も確かにされている分離レベルに応じて、読み込みのために取得しました。具体的には、この場合、投稿者は複製されたデータベースを扱っておりshow processlist、ロックを実際に確認するために使用できることを明確に述べています。したがって、実際にはロックが取得されていると想定しても安全です。
クレイグ

1
答えは常に本当です。もちろん、いくつかのロックがあります-使用されるinnodb内のいくつかの内部ミューテックス(たとえば、innodbバッファープールミューテックス)。ほとんどのユーザーはこれらのロックを気にせず、気づかず、通常、DDL操作中にのみ競合します(16Gバッファープールがあり、別のスレッドで「ドロップテーブル」を実行する場合など)。ただし、デフォルトでは行ロックはかかりません。そういう意味です。答えはかなりあいまいでした。
MarkR 2013

1
いつも?トランザクション分離レベルがシリアル化可能に設定されている場合、またはselectステートメントがLOCK IN SHARE MODEを使用していて、自動コミットが無効になっている場合はどうなりますか?多くの(ほとんど/すべての)データベースサーバーが、真のシリアル化ではなくデフォルトでスナップショット分離を使用するようになったことを知っていますが、シリアル化可能な読み取りを強制する正当な理由がまだありませんか?しかし、リモートで通常のすべてのケースで、MySQLのデフォルト条件は他のスレッドに影響する読み取りロックを引き起こさないので、あなたが持っていない問題について心配しないでください。ところで、私は自分の反対票を取り消そうとしました。申し訳ありません...
クレイグ

3
「普段はしないで」と言った。通常の選択(FOR UPDATEまたはLOCK IN SHARE MODEなし)を実行し、デフォルトのトランザクション分離レベルを使用する場合を意味しました。分離レベルを変更する有効なケースはいくつかありますが、私はそれをセッションごとにのみ行い、デフォルトでは行いません。
MarkR 2013

0

mysqlでダーティリードを有効にする別の方法は、ヒントを追加することです:LOCK IN SHARE MODE

SELECT * FROM TABLE_NAME LOCK IN SHARE MODE; 

「自動コミットが1に設定されている場合、LOCK IN SHARE MODE句とFOR UPDATE句は効果がありません。」...そしてautocommit = 1がデフォルト
MartinZvaríkApr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.