Creating indexes for mysql under navicat leads to deadlock, database crash, perfect solution

written in front

DDL statements are to create, delete, and modify database objects (databases, tables, columns, indexes, etc.).

I shared an article before mysql creating an index leads to deadlock, database crash, and mysql table-level lock [meta data lock (MDL)] full solution

Through the previous article, we learned that MySQL has a table lock called metadata lock (meta data lock, MDL) metadata lock. When executing DDL, it will check the metadata lock and try to obtain it.

I used to think that as long as there are no long transactions in the MySQL database, you can execute DDL statements with peace of mind. We naively thought that in short transaction scenarios, DDL statements will always acquire metadata locks after the previous transaction ends. There is no risk of deadlock.

But found out recently! Things are not as simple as imagined! 就算是没有长事务,MySQL8.0在创建索引的时候,仍然有可能会导致死锁的发生!
Let's analyze it together.

Note! The operations in this article are all based on mysql 8.0.21the InnoDBengine and 可重复读事务隔离级别the next navicat13version.

In a non-navicat environment, the result may be different!

1. Scenario analysis of executing DDL statements in short transaction scenarios

First create a table:

CREATE TABLE `lock_test` (
  `id` int NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

1. In the short transaction scenario, perform the table field addition operation

insert image description here
We found that when transaction A has not been committed, transaction B and transaction C will be in a waiting state.

Once transaction A initiates the commit command, transaction B will be executed immediately, and the execution will be successful, and transaction C will also be executed successfully after transaction B.

In the whole process, only normal transactions wait, and no deadlock will occur.

2. In the short transaction scenario, perform table field modification operations

insert image description here
We found that the result of modifying fields is the same as that of adding fields.

3. In short transaction scenarios, delete table fields

insert image description here
When there is no data in the table, we will find that after transaction A commits, transaction B and transaction C enter a deadlock, and no SQL statement in the table can be executed at this time!

At this time, the database table is deadlocked, and the database SQL piles up more and more, causing the database to crash!

(1) Add a piece of data to try

INSERT INTO `lock_test`(`id`, `name`, `age`, `column_name`) VALUES (1, '1', 1, '1');

insert image description here
The situation with data is different from the situation without data!

When there is data, when transaction A is committed, transaction C will execute successfully, and when transaction C is committed, transaction B will finally execute successfully.

4. In short transaction scenarios, add index operations

Still keep the data in the database.

INSERT INTO `lock_test`(`id`, `name`, `age`, `column_name`) VALUES (1, '1', 1, '1');

insert image description here
We found that after transaction A commits, transaction B and transaction C enter a deadlock, and no SQL statement in the table can be executed at this time!

At this time, the database table is deadlocked, and the database SQL piles up more and more, causing the database to crash!

5. Summary

Speak with facts.

Through examples, we can see that even if there is no long transaction, executing DDL statements will still cause table deadlock.
Especially the operation on the index is very dangerous!

2. Perfect solution

1. Lock the entire table before executing DDL

Before executing the DDL statement, first ensure that there is no long transaction through the following SQL:

SELECT * FROM information_schema.INNODB_TRX;

Then, before executing the DDL statement, first lock the entire table, and then execute the DDL statement:
insert image description here
Use the following operations to perfectly solve the deadlock problem!

-- 锁整表,加上写锁
lock table lock_test write;
-- 添加索引
CREATE INDEX index_tb ON lock_test(column_name);
-- 解锁
unlock table;

2. Set the timeout period before executing DDL

When altering table, set the waiting time. It is best if you can get the MDL write lock within the specified waiting time. If you can’t get it, don’t block the subsequent business statement, give up first. The developer or DBA then repeats the process by retrying the command.

-- 单位 秒,只在当前会话中生效
set lock_wait_timeout=10
-- 添加索引
CREATE INDEX index_tb ON lock_test(column_name);

3. Reason analysis

When changing the index on a non-primary key field, it is not an atomic operation. The non-primary key field index will be updated first, and then the primary key index will be updated.

When we delete the primary key:

insert image description here
This situation is exactly the same as the scenario where the table field deletion operation is performed when there is data in the table.

The reason is OnLine-DDL introduced by MySQL5.6. A DDL statement actually contains two waiting operations:

  • Prepare stage: try to acquire the MDL exclusive lock, prohibiting other threads from reading and writing;
  • DDL execution phase: Downgrade to MDL shared lock, allowing other threads to read;
  • Commit stage: Upgrade to MDL exclusive lock, prohibiting other threads from reading and writing;
  • Finish stage: Release the MDL lock;
    1, 3, 4 If there is no lock conflict, the execution time is very short. The second step takes up most of the DDL time, during which the table can read and write data normally, so it is called "online".
    If the MDL write lock in step 3 is upgraded to an MDL write lock, the MDL lock of this table is occupied by other transactions, then this transaction will be blocked until the MDL write lock can be obtained, and if unfortunately it has not been obtained, the lock will eventually time out. Just roll back the DDL operation.
    Therefore, only when the DDL statement starts and ends, reading and writing are prohibited, and reading is allowed when the statement is executed.

1. Verify OnLine-DDL

insert image description here
We found that transaction C, replaced by an Update statement, does not cause deadlock.

Because OnLine-DDL is a write lock-read lock-write lock, there is a process of lock downgrade and upgrade.
OnLine-DDL is not an atomic operation for the select statement, and it is divided into two steps (locking relative to select when writing a lock, unlocking relative to select when reading a lock, and locking select when writing a lock).
For the update statement, it is an atomic operation, which is equivalent to adding a lock throughout the process.

written in the back

If this article is helpful to you, please like, collect and follow~
insert image description here

Guess you like

Origin blog.csdn.net/A_art_xiang/article/details/129444340