MySQL8.0・エンジン分析・InnoDB history listが0に下がらない理由


アリ雲ブログから抜粋し、原文アドレス:https://yq.aliyun.com/articles/400891?spm=a2c4e.11153959.blogcont341036.25.7d001098OH5qbi
InnoDBに詳しい友人は、innodbのhistory list長さがundoログがどれだけ整理されていないかを表していることを知っています.show engine innodb statusコマンドで入手できます.historyリストの長さが大きい場合は、インスタンスの複雑さが非常に高いか、大きなクエリーがある可能性があるか、トランザクションがコミットされていないため、Undologは分析できません.
しかし、よく観察すると、history listが0に下がらないことに気づいたかどうか、一度slow shutdownをしてもだめだ.理論的にはundoログがpurgeできれいになったら、理論的には0に下がるはずだからです.
よりよく理解するために、私たちはまずいくつかの概念を普及させます.まずinnodbは複数のrollback segmentをサポートし、各segmentは約1024個のslotを含む.
トランザクションが開始されると、どのrollback segmentを使用するかを指定し、実際に操作を実行するときに特定のslotを割り当てます.通常、2つのslotがあります.
  • update_undo:トランザクション内でのみ使用されるupdate文
  • insert_undo:トランザクション内のinsert文のみ
  • 通常、トランザクションに1つの操作タイプしか含まれていない場合は、1つのslotのみが使用されます.ただし、insert操作などの例外もあります.insertのレコードがpage上にすでに存在していますが、無効であれば、この無効なレコードを更新することで挿入を実現することができます.この場合はupdate_を使用します.undo.
    なぜ2つのundo slotに分けて、1つのslotだけですべてを処理するのではありませんか?これは、コミットフェーズでのundo処理が異なるためです.
    Insert undoには、2つの処理方法があります
  • Free:新しく挿入されたレコードによって生成されたUndoがクエリー文に参照されないことを知っているので、undoを直接解放することができます.ここでのundo logはhistory list上の
  • に累加算されません.
  • reuse:undoが1つのpageしか占有されず、pageが一定の割合未満で使用されている場合(実際には、第2の条件はinsert undoに対して除去され得る)、cachd list上に配置され、再利用に備えられる.再利用時には、page resetがupdate_に対して削除されます.undo:
  • の2つの処理方法もあります.
  • Purge:ここでは、rollback segmentに対応するhistory listデータページのリストに追加します.history listの長さは1
  • です.
  • Reuse:undoもhistory listに追加され、history listの長さは1に追加されます.by the way、update undo、insertの再利用方法は異なり、undo pageにpageをリセットするのではなくundo log headerを新規作成します.これは、1つのundoページに複数のundo logが異なるトランザクションに属している可能性がありますが、1つだけアクティブである可能性があります.

  • では、最初の質問に戻ります.undo logがhistory listに追加された以上、なぜundo purgeが完了した後、0にリセットされなかったのでしょうか.
    次の関数を見てみましょう
        trx_purge_truncate
          trx_purge_truncate_history
                    trx_purge_truncate_rseg_history

    関数trx_purge_truncate_rseg_historyには、次のコード・セグメントがあります.
            if ((mach_read_from_2(seg_hdr + TRX_UNDO_STATE) == TRX_UNDO_TO_PURGE)
                && (mach_read_from_2(log_hdr + TRX_UNDO_NEXT_LOG) == 0)) {
    
                    /* We can free the whole log segment */
    
                    mutex_exit(&(rseg->mutex));
                    mtr_commit(&mtr);
    
                    trx_purge_free_segment(rseg, hdr_addr, n_removed_logs);
    
                    n_removed_logs = 0;
            } else {
                    mutex_exit(&(rseg->mutex));
                    mtr_commit(&mtr);
            }

    ここで特殊な判断をして、状態がPURGEのundo logだけがfree segmentクリーンアップをしました.cached状態のundoはその場に残る.個人的な推測では、これらのundo logは再利用として残すことができ、再利用後、一度にクリーンアップすることができるからです.
    推測を検証するために、関数trx_を変更します.undo_set_state_at_finish、undo log状態、またはTRX_UNDO_TO_FREE、またはTRX_UNDO_TO_PURGE.
    インスタンスに一定の負荷を加えて、slow shutdownの再起動をもう一度行うと、history list lengthの長さはやはり0になります.0にリセットできないのはcached undoによるものであることを確認した.