1. Query optimization
1.1. MySQL Optimization Principles
Mysql tuning outline
- Slow query open and capture
- Explain + slow SQL analysis
- Run the show profile command to query the execution details and life cycle of SQL on the Mysql server
- Tuning parameters of the SQL database server
A permanent small table drives a larger table, similar to Nested Loop Nested Loop
- The EXISTS grammar:
SELECT ... FROM table WHERE EXISTS(subquery)
- This syntax can be interpreted as: put the query data into the sub-query to perform conditional verification. According to the verification result (TRUE or FALSE), the data result of the main query can be preserved.
- EXISTS(subquery) returns only TRUE or FALSE, therefore in the subquery
SELECT *
It can also beSELECT 1
The official statement is that the actual execution will ignore the SELECT list, so there is no difference - The actual execution of the EXISTS subquery may be optimized rather than compared item by item in our understanding. If there are concerns about efficiency, actual tests can be performed to determine efficiency.
- The EXISTS subquery can also be replaced by conditional expression, other subquery or JOIN. The optimal type needs to be analyzed on a case-by-case basis
Conclusion:
- Always remember that small tables drive large tables
- When the table B dataset is smaller than the table A dataset, use in
- When the data set of table A is smaller than that of table B, exist is used
Usage of in and exists
- Tbl_emp table and TBL_DEPT table
select * from tbl_emp;
+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
| 8 | s9 | 51 |
+----+------+--------+
8 rows in set (0.00 sec)
select * from tbl_dept;
+----+----------+--------+
| id | deptName | locAdd |
+----+----------+--------+
| 1 | RD | 11 |
| 2 | HR | 12 |
| 3 | MK | 13 |
| 4 | MIS | 14 |
| 5 | FD | 15 |
+----+----------+--------+
5 rows in set (0.00 sec)
Copy the code
- In the writing of
select * from tbl_emp e where e.deptId in (select id from tbl_dept);
+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
+----+------+--------+
7 rows in set (0.00 sec)
Copy the code
- The exists of writing
select * from tbl_emp e where exists (select 1 from tbl_dept d where e.deptId = d.id);
+----+------+--------+
| id | NAME | deptId |
+----+------+--------+
| 1 | z3 | 1 |
| 2 | z4 | 1 |
| 3 | z5 | 1 |
| 4 | w5 | 2 |
| 5 | w6 | 2 |
| 6 | s7 | 3 |
| 7 | s8 | 4 |
+----+------+--------+
7 rows in set (0.00 sec)
Copy the code
1.2, ORDER BY optimization
ORDER BY clause, try to use Index rather than FileSort
Create a table
- Build table SQL
create table tblA(
#id int primary key not null auto_increment,
age int,
birth timestamp not null
);
insert into tblA(age, birth) values(22, now());
insert into tblA(age, birth) values(23, now());
insert into tblA(age, birth) values(24, now());
create index idx_A_ageBirth on tblA(age, birth);
Copy the code
- Test data in tblA tables
select * from tblA;
+------+---------------------+
| age | birth |
+------+---------------------+
| 22 | 2020- 08- 05 10:36:32 |
| 23 | 2020- 08- 05 10:36:32 |
| 24 | 2020- 08- 05 10:36:32 |
+------+---------------------+
3 rows in set (0.00 sec)
Copy the code
- Indexes in TBL
SHOW INDEX FROM tblA;
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+ ------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+ ------------+---------+---------------+
| tblA | 1 | idx_A_ageBirth | 1 | age ` | A | 3 | NULL | NULL | YES | BTREE | | |
| tblA | 1 | idx_A_ageBirth | 2 | birth | A | 3 | NULL | NULL | | BTREE | | |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+ ------------+---------+---------------+
2 rows in set (0.00 sec)
Copy the code
CASE1: The case where you can sort using an index
- Only the lead brother age
EXPLAIN SELECT * FROM tblA where age>20 order by age;
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------+
| 1 | SIMPLE | tblA | index | idx_A_ageBirth | idx_A_ageBirth | 9 | NULL | 3 | Using where; Using index |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------+
1 row in set (0.01 sec)
EXPLAIN SELECT * FROM tblA where birth>'2016-01-28 00:00:00' order by age;
+----+-------------+-------+-------+---------------+----------------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+----------------+---------+------+------+--------------------------+
| 1 | SIMPLE | tblA | index | NULL | idx_A_ageBirth | 9 | NULL | 3 | Using where; Using index |
+----+-------------+-------+-------+---------------+----------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
Copy the code
- Age + birth
EXPLAIN SELECT * FROM tblA where age>20 order by age,birth;
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------+
| 1 | SIMPLE | tblA | index | idx_A_ageBirth | idx_A_ageBirth | 9 | NULL | 3 | Using where; Using index |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
Copy the code
- Mysql default ascending order, full ascending or full descending order, can withstand
EXPLAIN SELECT * FROM tblA ORDER BY age ASC, birth ASC;
+----+-------------+-------+-------+---------------+----------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+----------------+---------+------+------+-------------+
| 1 | SIMPLE | tblA | index | NULL | idx_A_ageBirth | 9 | NULL | 3 | Using index |
+----+-------------+-------+-------+---------------+----------------+---------+------+------+-------------+
1 row in set (0.00 sec)
EXPLAIN SELECT * FROM tblA ORDER BY age DESC, birth DESC;
+----+-------------+-------+-------+---------------+----------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+----------------+---------+------+------+-------------+
| 1 | SIMPLE | tblA | index | NULL | idx_A_ageBirth | 9 | NULL | 3 | Using index |
+----+-------------+-------+-------+---------------+----------------+---------+------+------+-------------+
1 row in set (0.01 sec)
Copy the code
CASE2: A case in which an index cannot be used for sorting
- The head brother age is dead
EXPLAIN SELECT * FROM tblA where age>20 order by birth;
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------- ---------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------- ---------------+
| 1 | SIMPLE | tblA | index | idx_A_ageBirth | idx_A_ageBirth | 9 | NULL | 3 | Using where; Using index; Using filesort |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------- ---------------+
1 row in set (0.01 sec)
Copy the code
- How dare I birth precede Age
EXPLAIN SELECT * FROM tblA where age>20 order by birth,age;
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------- ---------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------- ---------------+
| 1 | SIMPLE | tblA | index | idx_A_ageBirth | idx_A_ageBirth | 9 | NULL | 3 | Using where; Using index; Using filesort |
+----+-------------+-------+-------+----------------+----------------+---------+------+------+--------------------------- ---------------+
1 row in set (0.00 sec)
Copy the code
- Mysql default ascending order, if full ascending or full descending order, ok, but a rise or fall mysql can not carry
EXPLAIN SELECT * FROM tblA ORDER BY age ASC, birth DESC;
+----+-------------+-------+-------+---------------+----------------+---------+------+------+---------------------------- -+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+----------------+---------+------+------+---------------------------- -+
| 1 | SIMPLE | tblA | index | NULL | idx_A_ageBirth | 9 | NULL | 3 | Using index; Using filesort |
+----+-------------+-------+-------+---------------+----------------+---------+------+------+---------------------------- -+
1 row in set (0.00 sec)
Copy the code
conclusion
- MySQL supports two kinds of sorting methods, FileSort and Index. Index is more efficient, which means that MySQL scans the Index itself to complete sorting. FileSort is less efficient.
- ORDER BY satisfies both cases (the best left prefix rule) and will be sorted BY Index
- The ORDER BY statement uses the left-most front row of the index
- Use the where clause in combination with the OrderBy clause condition column to satisfy the left-most front of the index
- Do the sorting on the index column as much as possible, following the best left prefix for the index
If the index column is not sorted, mysql will start filesort’s two algorithms: double-path sort and single-path sort
- Dual sorting
- MySQL4.1 used double-path sorting, which literally means scanning the disk twice for data. Read the row pointer and the columns for the Order Derby operation, sort them, then scan the sorted list and re-read the corresponding data transfer from the list according to the values in the list
- Fetch the sort fields from disk, sort them in buffer, and fetch the other fields from disk.
- Single way sorting
- Fetching a batch of data requires two scans of the disk, which is notoriously time consuming for I/O, so after mysql4.1, there was an improved algorithm called single-way sort.
- It reads all the columns needed for the query from disk, sorts them by the columns to be Derby, and then scans the sorted list for output. It is faster, avoids a second read, and turns random I/O into sequential I/O, but uses more space. Because it keeps every line in memory.
- Conclusions and problems:
- Since single-path is an improved algorithm, it is generally better than dual-path
- In sort_buffer, method B takes up A lot more space than method A. Because method B takes out all fields, it is possible that the total size of the retrieved data exceeds the capacity of sort_buffer. As A result, only sort_buffer size can be retrieved each time for sorting (create TMP file, Sort_buffer = sort_buffer = sort_buffer = sort_buffer This results in multiple I/ OS.
- Conclusion: An attempt to save an I/O operation resulted in a large number of /O operations that were not worth the cost.
- Further optimization strategies:
- Increases the sort_buffer_size parameter setting
- Increases the setting of the max_LENGTH_FOR_sorT_DATA parameter
Follow these rules to increase the speed of Order By
- It is important to note that select * is a no-no in Order by and only Query the required fields. The impact here is:
- When total field size less than max_length_for_sort_data, Query and sort field is not a TEXT | BLOB, will use the improved algorithm, single channel sorting, or with the old algorithm, multiple sort.
- Both algorithms may exceed the sort_buffer capacity. After that, TMP files will be created for merge sorting, resulting in multiple I/ OS. However, using single-path sorting algorithm is more risky, so sort_buffer_size should be increased.
- Try increasing sort_BUFFer_SIZE Regardless of which algorithm you use, increasing this parameter will improve efficiency, depending on the system’s capabilities, of course, since this parameter is per-process
- Trying to increase max_LENGTH_FOR_sort_DATA Increasing this parameter increases the probability of using the improved algorithm. However, if set too high, the probability of total data capacity exceeding sort_BUFFer_size increases, with high disk I/O activity and low processor utilization evident.
Order By sort index optimization summary
1.3. GROUP BY optimization
Group by keyword optimization
- Group by is essentially sorted and then grouped, following the best left prefix for the index
- When index columns are unavailable, increase the max_LENGTH_FOR_sort_data parameter setting + increase the sort_BUFFer_SIZE parameter setting
- Where having is higher than where having can be qualified
- Other rules are consistent with Order by
2. Slowly query logs
2.1 introduction to slow Query logs
What is a slow query log?
- The slow query log of MySQL is used to record statements whose response time exceeds the threshold. In particular, SQL statements whose response time exceeds the value of long_query_time are recorded in the slow query log.
- The default value of long_query_time is 10, which means that SQL statements running for more than 10 seconds are logged
- He will check which SQL exceeds our maximum endurance time value. For example, if an SQL is executed for more than 5 seconds, we will consider it as slow SQL. We hope to collect SQL of more than 5 seconds and conduct comprehensive analysis based on previous explain.
2.2. Enable slow query logs
How to play?
Description:
- By default, slow query logging is disabled for the MySQL database. You need to set this parameter manually.
- Of course, it is generally not recommended to enable this parameter unless it is necessary for tuning, because slow query logging can have some performance impact. Slow query logs can be written to a file
Check whether and how to enable it
- Checking whether slow query logs are enabled:
- By default, the value of slow_query_log is OFF, indicating that slow query logging is disabled
- This can be enabled by setting the value of slow_query_log
- through
SHOW VARIABLES LIKE '%slow_query_log%';
Check whether slow query logs of mysql are enabled
SHOW VARIABLES LIKE '%slow_query_log%';
+---------------------+-------------------------------+
| Variable_name | Value |
+---------------------+-------------------------------+
| slow_query_log | OFF |
| slow_query_log_file | /var/lib/mysql/Heygo-slow.log |
+---------------------+-------------------------------+
2 rows in set (0.00 sec)
Copy the code
- How to Enable slow Query logs:
set global slow_query_log = 1;
Enable slow log query- use
set global slow_query_log=1
Slow log query takes effect only for the current database. If MySQL is restarted, it becomes invalid.
set global slow_query_log = 1;
Query OK, 0 rows affected (0.07 sec)
SHOW VARIABLES LIKE '%slow_query_log%';
+---------------------+-------------------------------+
| Variable_name | Value |
+---------------------+-------------------------------+
| slow_query_log | ON |
| slow_query_log_file | /var/lib/mysql/Heygo-slow.log |
+---------------------+-------------------------------+
2 rows in set (0.00 sec)
Copy the code
-
To be permanent, you must modify the configuration file my.cnf (as well as other system variables)
- Change the slow_query_log and slow_query_log_file parameters in the my.cnf file under [mysqld] and restart MySQL server.
- Also configure the following two lines into the my.cnf file
“`sql [mysqld] slow_query_log =1 slow_query_log_file=/var/lib/mysql/Heygo-slow.log “`
- Slow_query_log_file specifies the path where the slow_query_log_file log file will be stored. By default, host_name-slow.log is given (if slow_query_log_file is not specified).
After slow query logging is enabled, what KIND of SQL will be recorded in slow query?
- This is controlled by the long_query_time parameter, which by default is 10 seconds, command:
SHOW VARIABLES LIKE 'long_query_time%';
Check the threshold of slow SQL
SHOW VARIABLES LIKE 'long_query_time%';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.01 sec)
Copy the code
- You can change it using commands or in the my.cnf parameter.
- If the running time is exactly long_query_time, it will not be recorded. In other words, the mysql source code is greater than long_query_time, not greater than or equal to.
2.3. Example of Slow Query logs
Case on
- Check the threshold time of slow SQL. The default threshold time is 10s
SHOW VARIABLES LIKE 'long_query_time%';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)
Copy the code
- To set the threshold time for slow SQL, we set it to 3s
set global long_query_time=3;
Query OK, 0 rows affected (0.00 sec)
<div class="hljs-button {2}" data-title="Copy" data-report-click="{" spm" :" 1001.2101.3001.4259 & quot; }"></div></code><ul class="pre-numbering" style=""><li style="color: rgb(153, 153, 153);">1</li><li style="color: rgb(153, 153, 153);">2</li></ul></pre>
<ul><li>Why does the threshold time not change after setting?<ul><li>You need to reconnect or open a new callback to see the changed value.</li><li>Check the global long_query_time value:<code>show global variables like 'long_query_time';</code>Discovery has taken effect</li></ul> </li></ul>` ` `sql
set global long_query_time=3;
Query OK, 0 rows affected (0.00 sec)
SHOW VARIABLES LIKE 'long_query_time%';
+-----------------+-----------+
| Variable_name | Value |
+-----------------+-----------+
| long_query_time | 10.000000 |
+-----------------+-----------+
1 row in set (0.00 sec)
show global variables like 'long_query_time';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 3.000000 |
+-----------------+----------+
1 row in set (0.00 sec)
Copy the code
-
Record slow SQL for subsequent analysis
- A select Dui sleep (4); More than 3s will definitely be recorded in the log
select sleep(4); +----------+ | sleep(4) | +----------+ | 0 | +----------+ 1 row in set (4.00 sec) Copy the code
- The slow query log file is stored in /var/lib/mysql.and its suffix is -slow.log
[root@Heygo mysql]# cd /var/lib/mysql/ [root@Heygo mysql]# ls -L total amount176156 -rw-rw----. 1 mysql mysql 56 8月 3 19:08 auto.cnf drwx------. 2 mysql mysql 4096 8月 5 10:36 db01 -rw-rw----. 1 mysql mysql 7289 8月 3 22:38 Heygo.err -rw-rw----. 1 mysql mysql 371 8月 5 12:58 heygo-slow.log -rw-rw----. 1 mysql mysql 79691776 8月 5 10:36 IBdata1 -rw-rw----. 1 mysql mysql 50331648 8月 5 10:36 ib_logfile0 -rw-rw----. 1 mysql mysql 50331648 8月 3 19:08 ib_logfile1 drwx------. 2 mysql mysql 4096 8月 3 19:08 mysql srwxrwxrwx. 1 mysql mysql 0 8month3 22:38 mysql.sock drwx------. 2 mysql mysql 4096 8月 3 19:08 Performance_schema Copy the code
- View the content in slow query logs
[root@Heygo mysql]# cat Heygo-slow.log /usr/sbin/mysqld, Version: 5.649. (MySQL Community Server (GPL)). started with: Tcp port: 3306 Unix socket: /var/lib/mysql/mysql.sock Time Id Command Argument # Time: 200805 12:58:01 # User@Host: root[root] @ localhost [] Id: 11 # Query_time: 4.000424 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0 SET timestamp=1596603481; select sleep(4); Copy the code
-
To query the number of Slow_queries in the current system: show global status like ‘%Slow_queries%’;
show global status like '%Slow_queries%'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | Slow_queries | 1 | +---------------+-------+ 1 row in set (0.00 sec) Copy the code
Slow query logs of the configuration edition
In /etc/my.cnf file under the [mysqld] node
slow_query_log=1; slow_query_log_file=/var/lib/mysql/Heygo-slow.log long_query_time=3; log_output=FILE Copy the code
Log analysis command mysqldumpslow
What is mysqlDumpslow?
In a production environment, if you need to manually analyze logs, find and analyze SQL, it is obviously a manual task. MySQL provides the log analysis tool mysqlDumpslow.
See help for mysqlDumpslow
[root@Heygo mysql]# mysqldumpslow --helpUsage: mysqldumpslow [ OPTS... ] [ LOGS... ] Parseand summarize the MySQL slow query log. Options are --verbose verbose --debug debug --help write this text to standard output -v verbose -d debug -s ORDER what to sort by (al, at, ar, c, l, r, t), 'at' is default al: average lock time ar: average rows sent at: average query time c: count l: lock time r: rows sent t: query time -r reverse the sort order (largest last instead of first) -t NUM just show the top n queries -a don't abstract all numbers to N and strings to 'S' -n NUM abstract numbers with at least n digits within names -g PATTERN grep: only consider stmts that include this string -h HOSTNAME hostname of db server for *-slow.log filename (can be wildcard), default is '*', i.e. match all -i NAME name of server instance (if using mysql.server startup script) -l don't subtract lock time from total time Copy the code
Mysqldumpshow Parameter description
- S: Indicates how to sort
- C: Access times
- L: Lock time
- R: Returns a record
- T: Query time
- Al: Average lock time
- Ar: average number of returned records
- At: indicates the average query time
- T: that is, how many previous columns of data are returned
- G: Followed by a regular matching pattern, case insensitive
Common Parameter Manual
-
Get the 10 SQL that return the most recordsets
mysqldumpslow -s r -t 10 /var/lib/mysql/Heygo-slow.log Copy the code
-
Get the 10 most frequently accessed SQL
mysqldumpslow -s c- t 10/var/lib/mysql/Heygo-slow.log Copy the code
-
Get the top 10 queries in chronological order that contain the left join
mysqldumpslow -s t -t 10 -g "left join" /var/lib/mysql/Heygo-slow.log Copy the code
-
Additional Suggestions when using these commands | and more use, otherwise likely explodes the screen
mysqldumpslow -s r -t 10 /var/lib/mysql/Heygo-slow.log | more Copy the code
3. Batch data scripts
Create a table
- Build table SQL
CREATE TABLE dept ( deptno int unsigned primary key auto_increment, dname varchar(20) not null default "", loc varchar(8) not null default "" )ENGINE=INNODB DEFAULT CHARSET=utf8; CREATE TABLE emp ( id int unsigned primary key auto_increment, empno mediumint unsigned not null default 0, ename varchar(20) not null default "", job varchar(9) not null default "", mgr mediumint unsigned not null default 0, hiredate date not null, sal decimal(7.2) not null, comm decimal(7.2) not null, deptno mediumint unsigned not null default 0 )ENGINE=INNODB DEFAULT CHARSET=utf8; Copy the code
Set the parameters
-
This function has none of DETERMINISTIC…
-
Since querying logs is too slow, since we have bin-log enabled, we must specify a parameter for our function.
log_bin_trust_function_creators = OFF
By default, you must pass an argument to function
show variables like 'log_bin_trust_function_creators'; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | log_bin_trust_function_creators | OFF | +---------------------------------+-------+ 1 row in set (0.00 sec) Copy the code
- through
set global log_bin_trust_function_creators=1;
We don’t need to pass parameters to function
set global log_bin_trust_function_creators=1; Query OK, 0 rows affected (0.00 sec) show variables like 'log_bin_trust_function_creators'; +---------------------------------+-------+ | Variable_name | Value | +---------------------------------+-------+ | log_bin_trust_function_creators | ON | +---------------------------------+-------+ 1 row in set (0.00 sec) Copy the code
-
If mysqld is restarted, the above parameters will disappear again.
- For Windows: my.ini –> [mysqld
log_bin_trust_function_creators=1
- /etc/my.cnf –> [mysqld
log_bin_trust_function_creators=1
- For Windows: my.ini –> [mysqld
Create functions that make sure each piece of data is different
- A function that randomly generates strings
Delimiter $$# Two $$marks the endcreate function rand_string(n int) returns varchar(255) begin declare chars_str varchar(100) default 'abcdefghijklmnopqrstuvwxyz'; declare return_str varchar(255) default ' '; declare i int default 0; while i < n do set return_str = concat(return_str,substring(chars_str,floor(1+rand()*52),1)); set i=i+1; end while; return return_str; end $$ Copy the code
- A function that randomly generates department numbers
delimiter $$ create function rand_num() returns int(5) begin declare i int default 0; set i=floor(100+rand()*10); return i; end $$ Copy the code
Creating a stored procedure
- Create a stored procedure to insert data into the EMP table
delimiter $$ create procedure insert_emp(in start int(10),in max_num int(10)) begin declare i int default 0; set autocommit = 0; repeat set i = i+1; insert into emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values((start+i),rand_string(6),'salesman'.0001,curdate(),2000.400,rand_num()); until i=max_num end repeat; commit; end $$ Copy the code
- Create a stored procedure to insert data into the DEPT table
delimiter $$ create procedure insert_dept(in start int(10),in max_num int(10)) begin declare i int default 0; set autocommit = 0; repeat set i = i+1; insert into dept(deptno,dname,loc) values((start+i),rand_string(10),rand_string(8)); until i=max_num end repeat; commit; end $$ Copy the code
Calling a stored procedure
- Insert 10 records into the DEPT table
DELIMITER ; CALL insert_dept(100.10); Copy the code
select * from dept; +--------+---------+--------+ | deptno | dname | loc | +--------+---------+--------+ | 101 | aowswej | syrlhb | | 102 | uvneag | pup | | 103 | lps | iudgy | | 104 | jipvsk | ihytx | | 105 | hrpzhiv | vjb | | 106 | phngy | yf | | 107 | uhgd | lgst | | 108 | ynyl | iio | | 109 | daqbgsh | mp | | 110 | yfbrju | vuhsf | +--------+---------+--------+ 10 rows in set (0.00 sec) Copy the code
- Insert 50w records into the emp table
DELIMITER ; CALL insert_emp(100001.500000); Copy the code
select * from emp limit 20; +----+--------+-------+----------+-----+------------+---------+--------+--------+ | id | empno | ename | job | mgr | hiredate | sal | comm | deptno | +----+--------+-------+----------+-----+------------+---------+--------+--------+ | 1 | 100002 | ipbmd | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 101 | | 2 | 100003 | bfvt | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 107 | | 3 | 100004 | | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 109 | | 4 | 100005 | cptas | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 101 | | 5 | 100006 | ftn | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 108 | | 6 | 100007 | gzh | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 102 | | 7 | 100008 | rji | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 100 | | 8 | 100009 | | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 106 | | 9 | 100010 | tms | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 100 | | 10 | 100011 | utxe | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 101 | | 11 | 100012 | vbis | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 104 | | 12 | 100013 | qgfv | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 104 | | 13 | 100014 | wrvb | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 105 | | 14 | 100015 | dyks | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 109 | | 15 | 100016 | hpcs | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 101 | | 16 | 100017 | fxb | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 108 | | 17 | 100018 | vqxq | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 102 | | 18 | 100019 | rq | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 102 | | 19 | 100020 | l | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 106 | | 20 | 100021 | lk | salesman | 1 | 2020- 08- 05 | 2000.00 | 400.00 | 100 | +----+--------+-------+----------+-----+------------+---------+--------+--------+ 20 rows in set (0.00 sec) Copy the code
4, Show the Profile
What is Show Profile?
- Mysql provides resources that can be used to analyze the resource consumption of statement execution in the current session. Can be used for tuning measurements of SQL
- Website: http://dev.mysql.com/doc/refman/5.5/en/show-profile.html
- By default, the parameter is turned off and the results of the last 15 runs are saved
Analysis steps
Check whether the current SQL version supports Show Profile
- Show variables like ‘% profiling; Check whether Show Profile is enabled
show variables like 'profiling%'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | profiling | OFF | | profiling_history_size | 15 | +------------------------+-------+ 2 rows in set (0.01 sec) Copy the code
Enable the Show Profile function. The function is disabled by default
set profiling=on;
Open the Show Profile
set profiling=on; Query OK, 0 rows affected, 1 warning (0.00 sec) show variables like 'profiling%'; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | profiling | ON | | profiling_history_size | 15 | +------------------------+-------+ 2 rows in set (0.00 sec) Copy the code
Run the SQL
- Normal SQL
select * from tbl_emp; select * from tbl_emp e inner join tbl_dept d on e.deptId = d.id; select * from tbl_emp e left join tbl_dept d on e.deptId = d.id; Copy the code
- Slow SQL
select * from emp group by id%10 limit 150000; select * from emp group by id%10 limit 150000; select * from emp group by id%10 order by 5; Copy the code
View the results
- Through the show profiles; Command view result
show profiles; +----------+------------+----------------------------------------------------------------------+ | Query_ID | Duration | Query | +----------+------------+----------------------------------------------------------------------+ | 1 | 0.00052700 | show variables like 'profiling%' | | 2 | 0.00030300 | select * from tbl_emp | | 3 | 0.00010650 | select * from tbl_emp e inner join tbl_dept d on e.'deptId' = d.'id' | | 4 | 0.00031625 | select * from tbl_emp e inner join tbl_dept d on e.deptId = d.id | | 5 | 0.00042100 | select * from tbl_emp e left join tbl_dept d on e.deptId = d.id | | 6 | 0.38621875 | select * from emp group by id%20 limit 150000 | | 7 | 0.00014900 | select * from emp group by id%20 order by 150000 | | 8 | 0.38649000 | select * from emp group by id%20 order by 5 | | 9 | 0.06782700 | select COUNT(*) from emp | | 10 | 0.35434400 | select * from emp group by id%10 limit 150000 | +----------+------------+----------------------------------------------------------------------+ 10 rows in set.1 warning (0.00 sec) Copy the code
Diagnosis of SQL
Show profile CPU, block IO for query SQL number;
View the specific flow of SQL statement execution and how long each step takes
show profile cpu, block io for query 2; +----------------------+----------+----------+------------+--------------+---------------+ | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | +----------------------+----------+----------+------------+--------------+---------------+ | starting | 0.000055 | 0.000000 | 0.000000 | 0 | 0 | | checking permissions | 0.000007 | 0.000000 | 0.000000 | 0 | 0 | | Opening tables | 0.000011 | 0.000000 | 0.000000 | 0 | 0 | | init | 0.000024 | 0.000000 | 0.000000 | 0 | 0 | | System lock | 0.000046 | 0.000000 | 0.000000 | 0 | 0 | | optimizing | 0.000018 | 0.000000 | 0.000000 | 0 | 0 | | statistics | 0.000008 | 0.000000 | 0.000000 | 0 | 0 | | preparing | 0.000019 | 0.000000 | 0.000000 | 0 | 0 | | executing | 0.000003 | 0.000000 | 0.000000 | 0 | 0 | | Sending data | 0.000089 | 0.000000 | 0.000000 | 0 | 0 | | end | 0.000004 | 0.000000 | 0.000000 | 0 | 0 | | query end | 0.000003 | 0.000000 | 0.000000 | 0 | 0 | | closing tables | 0.000005 | 0.000000 | 0.000000 | 0 | 0 | | freeing items | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | | cleaning up | 0.000006 | 0.000000 | 0.000000 | 0 | 0 | +----------------------+----------+----------+------------+--------------+---------------+ 15 rows in set.1 warning (0.00 sec) Copy the code
- Parameter Remarks:
- ALL: displays ALL cost information
- BLOCK IO: displays the BLOCK I/O costs
- CONTEXT SWITCHES: Costs related to CONTEXT SWITCHES
- CPU: displays CPU costs
- IPC: displays the cost information about sending and receiving
- MEMORY: displays MEMORY costs
- PAGE FAULTS: Displays overhead information related to PAGE errors
- SOURCE: displays the cost information associated with Source_function, Source_file, and Source_line
- SWAPS: Displays information about the cost associated with the number of SWAPS
Daily development needs attention to conclusions
- Converting HEAP to MyISAM: The result of the query is too large to have enough memory to move to disk.
- Creating TMP table: Creating a temporary table. Mysql will copy data to the temporary table and delete the temporary table when it is used up
- Copying to TMP tables on disk: Danger!!
- Locked: lock table
For example,
It’s weird… The teacher’s slow SQL I how can not reproduce, the following is the teacher’s example
5. Query logs globally
Never turn this on in production.
Enable global log query
- Mysql my.cnf = my.cnf
# open general_log=1Path general_log_file to record the log file=/path/Logfile # The output format is log_output=FILE Copy the code
Encoding enables global query logging
- Run the following command to enable global log query
set global general_log=1; set global log_output='TABLE'; Copy the code
- After that, your SQL statements will be logged to the general_log table in the mysql database, which can be viewed using the following command
select * from mysql.general_log; Copy the code
select * from mysql.general_log; +---------------------+---------------------------+-----------+-----------+--------------+------------------------------- ----------------+ | event_time | user_host | thread_id | server_id | command_type | argument | +---------------------+---------------------------+-----------+-----------+--------------+------------------------------- ----------------+ | 2020- 08- 05 14:41:07 | root[root] @ localhost [] | 14 | 0 | Query | select * from emp group by id%10 limit 150000 | | 2020- 08- 05 14:41:12 | root[root] @ localhost [] | 14 | 0 | Query | select COUNT(*) from emp | | 2020- 08- 05 14:41:30 | root[root] @ localhost [] | 14 | 0 | Query | select * from mysql.general_log | +---------------------+---------------------------+-----------+-----------+--------------+------------------------------- ----------------+ 3 rows in set (0.00 sec) Copy the code