mysql combat 19 | Why do I only check one line statement, also performs so slow?

Under normal circumstances, if I tell you query performance optimization, you first think of some complex statements, think of a query needs to return large amounts of data. But in some cases, "check line", will perform a particularly slow. Today, I just like to talk to you this interesting topic to see under what circumstances, will appear this phenomenon.

It should be noted that if the MySQL database itself is a lot of pressure, leading to the database server CPU utilization is high or ioutil (IO utilization) is very high, all statements in this case are likely to slow down, do not belong we discuss the scope of today.

For ease of description, I constructed a table, based on this table to explain today's problems. This table has two fields id and c, and I inserted 100,000 rows in it.

mysql> CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

delimiter ;;
create procedure idata()
begin
  declare i int;
  set i=1;
  while(i<=100000) do
    insert into t values(i,i);
    set i=i+1;
  end while;
end;;
delimiter ;

call idata();
复制代码

Next, I would use several different scenarios, for example, some of the previous article, we have introduced the knowledge, you see if you can see through, to test it.

The first category: the query does not return for a long time

1, execute the following SQL statement in Table t:

mysql> select * from t where id=1;
复制代码

Query results for a long time do not return.


                     Figure 1 query does not return for a long time

Generally encountered such a situation, it is a big probability table t is locked. Next Analysis of reasons, usually performed first at show processlist command to see what state the current statement.

Then we for each state, to analyze their causes, how to reproduce, and how to handle.

MDL lock, etc.

2, is to use the command to view the show processlist Waiting for a schematic diagram of metadata lock table.


                                   FIG 2 Waiting for table metadata lock showing a state

It appears This status means that now there is a request or table thread is held by MDL write lock on t, the select statement is blocked.

In the sixth article "Global and table locks: add a field to the table how there are so many hinder? "I introduce you to live a reproducible method. But it should be noted that the reproduction process is based on MySQL 5.6 version. The MySQL 5.7 release modifies the MDL locking strategy, so it can not reproduce the scene.

However, in MySQL 5.7 version reproduce this scene, it is also very easy. As shown in FIG. 3, I give a simple reproduction step.


           FIG 3 MySQL reproducing step Waiting for table metadata lock 5.7

session A write lock held by t MDL table lock table command, query and session B of MDL need to get a read lock. Therefore, session B enters a waiting state.

Way to deal with such problems is to find someone who holds MDL write lock, then kill it off.

However, since the inside of the results show processlist, Command column session A is "Sleep", resulting in very easy to find. But later with performance_schema sys and system libraries, much more convenient. (Need to set performance_schema = on MySQL is started, there will be set to off as compared to the performance loss of about 10%)

Sys.schema_table_lock_waits by querying this table, we can find out the process id directly causing obstruction, this disconnect can kill orders.


                              4 plus table lock seized the thread id

And so flush

Next, I'll give you another check on the status to be blocked.

I'm on the table t, execute the following SQL statement:

mysql> select * from information_schema.processlist where id=1;
复制代码

Here, I would like to secrecy.

You can look at Figure 5. I checked out this thread status is Waiting for table flush, you can imagine this is why.


                                      A schematic view of FIG. 5 Waiting for table flush state

This status means that now there is a thread on the table was about to do t flush operation. MySQL table to do inside to flush usage, generally have the following two:

flush tables t with read lock;

flush tables with read lock;
复制代码

Both flush statement, if the specified table t, then, represents the only table close t; If you do not specify a specific table name, then close all open tables in MySQL.

But normally these two statements execute very quickly, unless they are blocked by another thread.

So the situation may appear Waiting for table flush state is: there is a flush tables command blocked by another statement, then it blocked our select statement.

Now, we take a look at this case reproduce, reproduce the steps shown in Figure 6:


                            FIG 6 Waiting for table flush reproducing step of

In session A, I deliberately called once for each row sleep (1), so this statement by default to execute 100,000 seconds, during which the table t has been session A "open" with. Then, flush tables session B t of the command and then go off the table t, it is necessary in the other end of the query session A. In this way, session C to query again, it would be flush command blocked.

FIG 7 is a result of the current step show processlist complex. The investigation of this case is very simple, you see the result of this show processlist, certainly know how to do it.


                         Results show processlist FIG. 7 Waiting for table flush of

 

 Row lock, etc.

Now, after a table-level lock test, we finally came to the select statement in the engine.

mysql> select * from t where id=1 lock in share mode; 
复制代码

Usage above this statement you are very familiar with, our first 8 "Transactions in the end is isolated or not isolated? "As mentioned at the article describes the current reading.

Because access id = 1 this record to add a read lock, if this time there is already a transaction holds a write lock on the record this line, we select statement will be blocked.

Steps to reproduce and live as follows:


                                                 FIG 8 row lock recurring

                                      9 row lock scene show processlist

Obviously, session A started a transaction, possession write locks, do not submit, is the cause of session B is blocked.

The problem is not difficult to analyze, but the question is how to find out who occupied the write lock. If you are using a version of MySQL 5.7, you can be found by sys.innodb_lock_waits table.

Query method is:

mysql> select * from t sys.innodb_lock_waits where locked_table=`'test'.'t'`\G
复制代码


                                      10 through FIG. Sys.innodb_lock_waits lock check OK

You can see, this information is very wide, 4 threads are caused by blockage of the culprit. And get rid of the culprit this way is KILL QUERY 4 or KILL 4.

However, there should not be displayed "KILL QUERY 4". This command indicates to stop Statement No. 4 currently executing thread, and this method is actually of no use. Because possession row lock is an update statement, this statement has been executed before the completion of the now executed KILL QUERY, so that the transaction can not remove the lock on the row id = 1.

In fact, KILL 4 to be effective, that is to say directly disconnect the connection. Here it is the logic implied a connection when they were disconnected, automatically rolls back inside the thread connection is being executed, will release the lock on the row id = 1.

The second category: Query Slow

After numerous letters "lock", let us look at some examples of queries slow.

You must know first look at a SQL statement of reasons:

mysql> select * from t where c=50000 limit 1;
复制代码

Since there is no index on the field c, this statement can only go id primary key order scanning, and therefore need to scan 50,000 lines.

As a confirmation, you can look at the slow query log. Note that all the statements recorded here for the slow log, I executed after connecting the first set long_query_time = 0, the slow query log time threshold is set to 0.


                                           Figure 11 slow log full table scan line 50000

Rows_examined display scan 50,000 lines. You might say, not very slow Yeah, returned 11.5 milliseconds, we are generally configured online more than one seconds is considered slow queries. But you have to remember: bad query is not necessarily slow queries. Our example there are only 100,000 rows, data volume up, then execution time is linear go up.

The number of scanning lines, therefore the implementation of slow, this is well understood.

But then, we only look at a scan line, but the implementation is very slow statements.

12, this example is a slow log. You can see, the statement is executed

mysql> select * from t where id=1;
复制代码

Although the number of scanning lines is one, but the execution time is as long as 800 milliseconds.


                                            12 scan line but the implementation is very slow

Is not it strange that these times are spent where?

If I go down to the slow log screenshot drop down a bit, you can see the next statement, select * from t where id = 1 lock in share mode, when performing scanning lines is one line, the execution time is 0.2 milliseconds.


                                  FIG 13 plus lock in share mode of slow log

It appears to be not more strange? It stands to reason also lock in share mode locking, time should be longer fishes ah.

Some students may already have the answer. If you do not answer, I'll give you a message, 14 is the result of the implementation of the output of these two statements.


                                        The output 14 of the two statements

The first statement of the query results in c = 1, with a lock in share mode statement returns c = 1000001. See here should have more students know why. If you still have no idea, then, do not worry. I should talk to you explain the steps to reproduce, and then analyze the reasons.


                                                              Reproduction step 15 in FIG.

You see, session A first with start transaction with consistent snapshot command starts a transaction, then session B began update statement.

After the session B after executing a million times update statement, id = 1 this line in what state? You can find the answer in Figure 16.


                                                     FIG state data of 16 id = 1

session B finished updating million times, generated 1 million to roll back log (undo log).

With lock in share mode of SQL statements, the current reading is therefore a direct result of this reading 1000001, so fast; and select * from t where id = 1 This statement, read consistency, it is necessary to start from 1000001, followed by the implementation undo log, performed after a million times, it will return 1 results.

Note, undo log record in fact, is "to change the 2 1", "2 to 3 into" such an operation logic, painted minus purpose is to facilitate you Figure 1.

summary

Today I give you in on a simple table, perform the "check line" may appear to be locked and slow implementation examples. Which it involves the concept of table locks, row locks and read consistency.

In actual use, hit the scene would be more complicated. But much the same, you can follow the positioning method I described in the article, to locate and solve the problem.

Finally, I left you a question now.

We read, for example, when locked, using this statement, select * from t where id = 1 lock in share mode. Because the index id, can be positioned directly to the line id = 1, so that the read lock is applied only on this line.

But if it is the following SQL statement,

begin;
select * from t where c=5 for update;
commit;
复制代码

The sequence of statements is how to lock it? Plus the lock is released when it?

You can put your ideas and verification methods written in the comments section, I will give my answer in the next reference at the end of an article. Thank you for listening, you are welcome to send this share to more friends to read together.

On the issue of time

In the last article, I leave you with the question, I hope that you can share with you encountered before, a similar scene in the article.

An interesting scene, it is worth saying. I took his question rewrite, the table structure is as follows:

mysql> CREATE TABLE `table_a` (
  `id` int(11) NOT NULL,
  `b` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `b` (`b`)
) ENGINE=InnoDB;

复制代码

Suppose now that table there, there are one million rows of data, including the value of b 10 million lines of data is '1234567890', assuming that such a statement is executed now reads:

mysql> select * from table_a where b='1234567890abcd';
复制代码

At this time, MySQL will be how to enforce it?

Ideally, MySQL see the field b is defined varchar (10), it must return to empty it. Unfortunately, MySQL did not.

Or that is the '1234567890abcd' get index which do match, certainly not be able to quickly determine the value of the index is not the tree b, also soon be able to return an empty result.

But in fact, MySQL is not doing so.

Executes the SQL statement is very slow, the process is this:

  1. When passed to the execution engine, do a character truncation. Because the engine which defines the length of the line is only 10, so only the first 10 bytes of the cut, it is '1234567890' into do match;
  2. Such data satisfy the conditions of 10 million lines;
  3. Because select *, so do 100,000 back to the table;
  4. However, after each table to identify the entire line back to the server determines a layer, not the value of b '1234567890abcd';
  5. The result is empty.

This example is a good complement to our article content. Although the implementation process may operate through function, but ultimately get the result, server layer or to do a judgment.


Reproduced in: https: //juejin.im/post/5d0368035188257a6b40e4c9

Guess you like

Origin blog.csdn.net/weixin_33724046/article/details/93183480