binlog format of MySQL log → discussion on the default isolation level of MySQL

Posted by morph07 on Mon, 03 Jan 2022 07:57:10 +0100

Background issues

Before talking about binlog, let's review the default isolation level of mainstream relational databases. It's the default isolation level, not the isolation levels of transactions. Don't be mistaken

1. What is the default isolation level of Oracle and SQL Server and MySQL?

2. Why is the default isolation level of MySQL RR?

In fact, this problem is not very rigorous. We know that MySQL 5.5 replaced InnoDB with MyISAM as the default storage engine of MySQL, and transactions have isolation level. As soon as MyISAM does not support transactions, this problem was not established before MySQL 5.5.

Strictly speaking, it should be: why is the default isolation level of transactions in MySQL 5.5 and later versions RR, or why is the default isolation level of transactions in InnoDB RR

I believe everyone can answer question 1. The default isolation level of Oracle and SqlServer is read committed (RC), while the default isolation level of MySQL is Repeatable Read (RR)

But for question 2, I believe many small partners will hesitate: Er, This, Angang, it's been too long. My memory is not very good

The naughty little friend may start to switch the topic: you talk about binlog when you talk about binlog. What is the default isolation level? Is the default isolation level of MySQL still related to binlog?

The landlord doesn't know whether they are related or not. Let's look down together

binlog format

Binlog full name: binary log, that is, binary log, sometimes called archive log, records all operations that have been changed to MySQL database, including table structure change (CREATE, ALTER, DROP TABLE...), table data modification (INSERT, UPDATE, DELETE...), However, operations such as SELECT and SHOW are not included because they do not modify the data itself; If the change operation does not cause changes to the database, the operation will also be written to the binlog, such as

update tbl_t1 set name = 'lisi' where name = '123'; It does not cause changes to the database, but it is still recorded in the binlog

binlog has three formats: state, ROW and MIXED. At first, there is only state, and then ROW and MIXED are derived

Before MySQL 5.1.5, the format of binlog was only state. From 5.1.5, binlog in ROW format was supported. From 5.1.8, MySQL began to support binlog in MIXED format

Before MySQL 5.7.7, the default format of binlog was state. In version 5.7.7 and later, binlog_ The default value of format is ROW

Let's look at what the binlog s of the three formats look like, what are their differences, and what are their advantages and disadvantages

STATEMENT

From the first version of MySQL to the latest version 8.0 x. STATEMENT has always been strong in binlog format, but since 5.7.7, it has retreated behind the scenes and given the top position to ROW

binglog is different from the code log in our development. It contains two types of files

index file: file name index, which log files are being used, as follows

Log file: filename. 00000*

Records all operations that have changed the MySQL database

Because the binlog log file is a binary file and cannot be opened directly with a text editor, it needs to be opened with a specific tool. MySQL provides mysqlbinlog to help us view the contents of the log file

There are many optional parameters for mysqlbinlog, mysqlbinlog exe --help

mysqlbinlog.exe Ver 3.3 for Win64 at x86
Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Dumps a MySQL binary log in a format usable for viewing or for piping to
the mysql command line client.

Usage: mysqlbinlog.exe [options] log-files
  -?, --help          Display this help and exit.
  --base64-output[=name]
                      Determine when the output statements should be
                      base64-encoded BINLOG statements: 'never' disables it and
                      works only for binlogs without row-based events;
                      'decode-rows' decodes row events into commented SQL
                      statements if the --verbose option is also given; 'auto'
                      prints base64 only when necessary (i.e., for row-based
                      events and format description events); 'always' prints
                      base64 whenever possible. 'always' is deprecated, will be
                      removed in a future version, and should not be used in a
                      production system.  --base64-output with no 'name'
                      argument is equivalent to --base64-output=always and is
                      also deprecated.  If no --base64-output[=name] option is
                      given at all, the default is 'auto'.
  --character-sets-dir=name
                      Directory for character set files.
  -d, --database=name List entries for just this database (local log only).
  --debug-check       Check memory and open file usage at exit .
  --debug-info        Print some debug info at exit.
  -D, --disable-log-bin
                      Disable binary log. This is useful, if you enabled
                      --to-last-log and are sending the output to the same
                      MySQL server. This way you could avoid an endless loop.
                      You would also like to use it when restoring after a
                      crash to avoid duplication of the statements you already
                      have. NOTE: you will need a SUPER privilege to use this
                      option.
  -F, --force-if-open Force if binlog was not closed properly.
                      (Defaults to on; use --skip-force-if-open to disable.)
  -f, --force-read    Force reading unknown binlog events.
  -H, --hexdump       Augment output with hexadecimal and ASCII event dump.
  -h, --host=name     Get the binlog from server.
  -l, --local-load=name
                      Prepare local temporary files for LOAD DATA INFILE in the
                      specified directory.
  -o, --offset=#      Skip the first N entries.
  -p, --password[=name]
                      Password to connect to remote server.
  -P, --port=#        Port number to use for connection or 0 for default to, in
                      order of preference, my.cnf, $MYSQL_TCP_PORT,
                      /etc/services, built-in default (3306).
  --protocol=name     The protocol to use for connection (tcp, socket, pipe,
                      memory).
  -R, --read-from-remote-server
                      Read binary logs from a MySQL server.
  -r, --result-file=name
                      Direct output to a given file.
  --server-id=#       Extract only binlog entries created by the server having
                      the given id.
  --set-charset=name  Add 'SET NAMES character_set' to the output.
  --shared-memory-base-name=name
                      Base name of shared memory.
  -s, --short-form    Just show regular queries: no extra info and no row-based
                      events. This is for testing only, and should not be used
                      in production systems. If you want to suppress
                      base64-output, consider using --base64-output=never
                      instead.
  -S, --socket=name   The socket file to use for connection.
  --start-datetime=name
                      Start reading the binlog at first event having a datetime
                      equal or posterior to the argument; the argument must be
                      a date and time in the local time zone, in any format
                      accepted by the MySQL server for DATETIME and TIMESTAMP
                      types, for example: 2004-12-25 11:25:56 (you should
                      probably use quotes for your shell to set it properly).
  -j, --start-position=#
                      Start reading the binlog at position N. Applies to the
                      first binlog passed on the command line.
  --stop-datetime=name
                      Stop reading the binlog at first event having a datetime
                      equal or posterior to the argument; the argument must be
                      a date and time in the local time zone, in any format
                      accepted by the MySQL server for DATETIME and TIMESTAMP
                      types, for example: 2004-12-25 11:25:56 (you should
                      probably use quotes for your shell to set it properly).
  --stop-position=#   Stop reading the binlog at position N. Applies to the
                      last binlog passed on the command line.
  -t, --to-last-log   Requires -R. Will not stop at the end of the requested
                      binlog but rather continue printing until the end of the
                      last binlog of the MySQL server. If you send the output
                      to the same MySQL server, that may lead to an endless
                      loop.
  -u, --user=name     Connect to the remote server as username.
  -v, --verbose       Reconstruct SQL statements out of row events. -v -v adds
                      comments on column data types.
  -V, --version       Print version and exit.
  --open-files-limit=#
                      Used to reserve file descriptors for use by this program.

Variables (--variable-name=value)
and boolean options {FALSE|TRUE}  Value (after reading options)
--------------------------------- ----------------------------------------
base64-output                     (No default value)
character-sets-dir                (No default value)
database                          (No default value)
debug-check                       FALSE
debug-info                        FALSE
disable-log-bin                   FALSE
force-if-open                     TRUE
force-read                        FALSE
hexdump                           FALSE
host                              (No default value)
local-load                        (No default value)
offset                            0
port                              3307
read-from-remote-server           FALSE
server-id                         0
set-charset                       (No default value)
shared-memory-base-name           (No default value)
short-form                        FALSE
socket                            E:/soft/mysql5.5.8/tmp/mysql.sock
start-datetime                    (No default value)
start-position                    4
stop-datetime                     (No default value)
stop-position                     18446744073709551615
to-last-log                       FALSE
user                              (No default value)
open-files-limit                  18432

These parameters are not discussed in detail. If you are interested, you can check them yourself. We focus on the contents of the log file and execute mysqlbinlog exe ../ data/mysql-bin. 000004

As you can see, the changes were made to the database

SQL is recorded in the log file in clear text. As for the advantages and disadvantages, we will compare them after reading the other two formats

ROW

In MySQL version 5.7.7 and later, the default format of binlog is ROW. Based on version 5.7.30, let's look at the content of ROW binlog

Generate database change operation first

The change operation has

binlog file currently being written by master: MySQL bin 00000 2, position from 2885 to 3929

Next, let's take a look at how to record in the log file and execute mysqlbinlog exe --start-position=2885 --stop-position=3929 ../ data/mysql-bin. 000002

It can be seen that the table structure change operation is recorded in the log file in the form of SQL in clear text (the same as state), but the table data change operation is recorded in the log file in the form of ciphertext, which is not convenient for us to read

Fortunately, mysqlbinlog provides the parameter - V , or - vv , to decrypt and view, and execute mysqlbinlog exe --base64-output=decode-rows -v --start-position=2885 --stop-position=3929 ../ data/mysql-bin. 000002

There is nothing to note about INSERT. Each column inserts the corresponding value

There is something to note about UPDATE. Although there is only one modified column and one condition column, what is recorded in the log is that the modified column is all columns, the condition column is all columns, and the column value is a specific value, rather than functions such as NOW() and UUID()

The table does not explicitly specify the primary key, and there is only one record that meets the update conditions. You can try: if there are multiple records that explicitly specify the primary key and meet the update conditions, see how binlog logs are recorded

DELETE is the same as UPDATE. Although there is only one condition column, all columns recorded in the log do

Compared with STATEMENT, it is more complex and contains a lot more content. Let's look at the advantages of the specific ROW

MIXED

Literally: mix, who does it mix? Who else can you mix? Intelligent hybrid STATEMENT and ROW

In most cases, binlog logs are recorded in the format of state (because the default isolation level of MySQL is RR, and few people modify the default isolation level). When the isolation level is RC mode, it is modified to ROW mode

Some special scenarios are also recorded in ROW format, so RR and RC are not distinguished

Of course, there is also a {NOW(), that is, only specific values are the most reliable. Other functions and system variables that depend on context and environment are not reliable because they will change according to context and environment

This will not show the specific log content. Interested partners will run the results by themselves

Summary of advantages and disadvantages

The three formats have been introduced. In contrast, I believe you have a certain understanding of their respective characteristics, advantages and disadvantages

One of the uses based on binlog: master-slave replication (three uses: master-slave replication, data recovery and audit). The landlord will summarize their advantages and disadvantages

MIXED's vision is good: it combines the advantages of state and ROW to produce a perfect format, but it backfires, and it will still have some problems

Compared with accuracy, performance priority will be lower (with the development of technology, hardware performance is no longer an unacceptable bottleneck), so ROW format is recommended

Relationship between MySQL binlog and its default isolation level RR

From the content of binlog format above, it seems that it has nothing to do with the default isolation level RR. Don't worry first and look down slowly

Under RC and state, each version of MySQL performs table data modification

The table engine is InnoDB, and the isolation level is RC and binlog_ Under the unified premise of format = state, let's take a look at mysql5 0.96,MySQL5.1.30,MySQL5.5.8,MySQL5.7.30 implementation of table data change operation

MySQl5.0.96 can be executed normally

MySQL5.1.30 execution error report and prompt

ERROR 1598 (HY000): Binary logging not possible. Message: Transaction level 'READ-COMMITTED' in InnoDB is not safe for binlog mode 'STATEMENT'

    MySQL5.5.8,MySQL5.7.30 execution error report, all prompts

ERROR 1665 (HY000): Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED.

In other words, mysql5 On and after 1.30, InnoDB of RC isolation level has no effect on binlog_format is limited and cannot be state, otherwise the table data cannot be modified

MySQL 4.x series, because the official does not provide download, it is impossible to test, there are 4 For version x (or version 5.1.x before 5.1.21), you can send me a private letter. Thank you very much!

The order in which operations of different session s are recorded in binlog

Let's use two sessions to perform the update operation. Let's see how the recording order of the operation records of different sessions in the binlog determines

You can see the update tbl_rr_test set age = 20 where id = 1; Execute first, then commit, update tbl_rr_test set age = 21 where id = 2; Execute later and commit first. The log records: the first commit is recorded in the front and the last commit is recorded in the back, which is independent of the execution time point; For a single session, it is easy to understand that the execution order is the recording order; If there are multiple sessions, commit first and record first

The main database changes the database in the order of execution time, while binlog records in the order of commit. Theoretically, the example problem in MySQL Bug23051 will occur

Relationship between default isolation level RR and binlog

Let's take a look at MySQL Bug23051. It is said that in the early version of MySQL 5.1, when the isolation level is RC and the binlog format is state, there are bugs in the master-slave replication of InnoDB (fixed in 5.1.21), while 5.0 X is no problem. We ran down the example in Bug23051 on 5.0.96

You can see that InnoDB under 5.0.96 is binlog at the RC level_ When format = state, UPDATE # t1 # SET # a=11 # where # b=2; If the transaction is not committed, then UPDATE # t1 # SET # b=2 # where # b=1; The transaction will be blocked, so the data will be OK when copying from the database

Therefore, from the previous point of view, from MySQL 5 Starting from 0, InnoDB is at RC level, binlog_ When format = state, there is no bug in the master-slave replication (no problem with 5.0, there is a problem with 5.1.x before 5.1.21, but it is not officially available for download. Versions 5.1.21 and later do not support setting binlog to state under RC isolation level)

Then the relationship between binlog and the default level RR is clear, which is what brother Yan said in what transaction isolation level mysql should choose in the [original] Internet Project:

that Mysql At 5.0 Before this version, binlog Only support STATEMENT This format! This format has been submitted before reading(Read Commited)At this isolation level, master-slave replication is possible bug Yes, so Mysql Will be repeatable(Repeatable Read)As the default isolation level!

In other words, on mysql5 Before 0, RR was used as the default isolation level to avoid most master-slave replication bugs, and then it has been used all the time; Why not avoid all master-slave replication bugs, because at the RR isolation level, binlog_ Under format = state, when using system functions (NOW(), UUID(), etc.), the master-slave data will still be inconsistent

summary

1. binlog three formats

At present, there are three mainstream MySQL binlog formats: state, ROW and MIXED. Considering data accuracy, ROW format is recommended

2. binlog default format

Before 5.1.5, MySQL only supported binlog in state format. Since 5.1.5, MySQL has supported binlog_format=ROW. Before MySQL 5.7.7, the default format of binlog was state. In version 5.7.7 and later, binlog_ The default value of format is ROW

3. Master slave copy bug (InnoDB engine)

For MySQL 5.1.30 and later, binlog cannot be enabled if RC isolation level is enabled under InnoDB_ Format = of the state

RC, RR isolation level, binlog_format=MIXED, there will still be data inconsistency in master-slave replication (affected by system functions)

RR isolation level, binlog_ Format = state, there will still be data inconsistency in master-slave replication (affected by system functions)

binlog_format=ROW, regardless of the RC isolation level or RR isolation level, there will be no data inconsistency in the master-slave replication

4. Why is MySQL's default isolation level RR

In order to avoid mysql5 The master-slave replication problem in versions before 0 has been used all the time

5. Engine selection problem

Since MySQL 5.6 and later, InnoDB has done a lot of optimization, and its performance is not lower than MyISAM. It is said that there is no special reason to give up MyISAM

Topics: Java Back-end architecture