MySQLでtrx_sys->mutexは色々な箇所から呼び出されている。これを長時間保持してるトランザクションがあるとMySQL全体の性能ダウンに繋がるというお話。
まとめ
- trx_sys->mutexはトランザクションの開始/終了時にも確保する必要がある
- 長時間保持して解放しないスレッドがいると他トランザクションの処理が進まないという状態になる
- 長時間保持するようなケースは実行頻度を減らすか代替案があればそちらを使用するにして回避する
詳細
実装自体はこんな感じ
InnoDBはSQLを実行する際はトランザクションで実行されます。各トランザクションが開始された後、そのトランザクションをグローバル トランザクション リストに追加する必要があり、グローバル トランザクション リストは trx_sys->mutex ミューテックスによって保護される必要があります。
/** Starts a transaction. */ static void trx_start_low( trx_t *trx, /*!< in: transaction */ bool read_write) /*!< in: true if read-write transaction */ { if (!trx_is_autocommit_non_locking(trx)) { // 自動コミットモードじゃないかつ非ロッキング読み取りクエリ /* If this is a read-only transaction that is writing to a temporary table then it needs a transaction id to write to the temporary table. */ if (read_write) { trx_sys_mutex_enter(); ut_ad(!srv_read_only_mode); trx->state.store(TRX_STATE_ACTIVE, std::memory_order_relaxed); trx->id = trx_sys_allocate_trx_id(); trx_sys->rw_trx_ids.push_back(trx->id); trx_sys_mutex_exit(); trx_sys_rw_trx_add(trx); } else { trx->state.store(TRX_STATE_ACTIVE, std::memory_order_relaxed); }
このコードは、MySQLデータベースのInnoDBストレージエンジン内部でトランザクションを開始するための関数trx_start_lowの実装を示しています。この関数は、新しいトランザクションを開始する際に、トランザクションオブジェクトの初期化や状態の更新など、いくつかの重要なステップを行います。以下に、コードの主要な部分を説明します。
事前条件のチェック ut_adマクロは、デバッグビルドでのみ有効なアサーションを提供します。これらは、関数が呼び出された時点で満たされているべき条件をチェックします(例えば、トランザクションがまだ開始されていない、ロールバック中ではない、など)。 トランザクションのプロパティの設定 trx->versionをインクリメントし、トランザクションのバージョンを更新します。 自動コミットの状態や、トランザクションが読み取り専用かどうかを設定します。読み取り専用トランザクションでは、いくつかの最適化が可能になります。
トランザクションIDの割り当て 読み取り書き込みトランザクションに対しては、持続的なリドゥログセグメント(trx_assign_rseg_durable)が割り当てられ、トランザクションIDが生成されます。 トランザクションシステムのミューテックス(trx_sys_mutex_enter/trx_sys_mutex_exit)を使用して、グローバルなトランザクションリストとIDの割り当てを保護します。
トランザクションの状態更新 トランザクションの状態がTRX_STATE_ACTIVEに更新され、アクティブなトランザクションリストに追加されます。これは、トランザクションが実際に作業を開始したことを意味します。
モニタリングとデバッグ MONITOR_INC(MONITOR_TRX_ACTIVE)は、アクティブなトランザクションの数をモニタリングするためのカウンタをインクリメントします。 コメントやDEBUG_SYNC_Cマクロを使用して、特定のポイントで同期を行ったり、デバッグ情報を提供したりします。
その他の考慮事項 コードは、トランザクションがデータベースディクショナリの操作などの特殊なケースであるかどうかもチェックし、それに応じて特別な処理を行います。 トランザクションが読み取り専用である場合、または自動コミットモードである場合の処理ロジックも含まれています。読み取り専用トランザクションや自動コミットトランザクションは、ロックやログのオーバーヘッドを減らすために特別に扱われることがあります。