記一次慢查詢的SQL優化
測試表結構
MariaDB [shoppings]> desc login_userinfo;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| num | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(16) | NO | UNI | NULL | |
| password | varchar(40) | NO | | NULL | |
| nickname | varchar(16) | NO | | NULL | |
| sex | varchar(10) | NO | | NULL | |
| settime | datetime(6) | NO | | NULL | |
| addr | varchar(32) | NO | | NULL | |
| email | varchar(32) | NO | | NULL | |
| phone | varchar(11) | NO | | NULL | |
| receiver | varchar(64) | NO | | NULL | |
| code | varchar(6) | NO | | NULL | |
| comment_id | int(11) | YES | MUL | NULL | |
+------------+-------------+------+-----+---------+----------------+
12 rows in set (0.003 sec)
表中數據量
MariaDB [shoppings]> select count(*) from login_userinfo;
+----------+
| count(*) |
+----------+
| 11809884 |
+----------+
1 row in set (2.503 sec)
分頁
MariaDB [shoppings]> select u.num, u.name, u.nickname, u.settime, u.addr,c.content from login_userinfo as u inner join login_comment as c on u.comment_id=c.id limit 10000000, 10;
+----------+--------------+--------------+----------------------------+------+---------+
| num | name | nickname | settime | addr | content |
+----------+--------------+--------------+----------------------------+------+---------+
| 20010049 | test20014998 | test20014998 | 2021-02-20 00:00:00.000000 | 深圳 | 不太行 |
| 20010050 | test20014999 | test20014999 | 2021-02-20 00:00:00.000000 | 北京 | 不太行 |
| 20010051 | test20015000 | test20015000 | 2021-02-20 00:00:00.000000 | 廣州 | 不太行 |
| 20010052 | test20015001 | test20015001 | 2021-02-20 00:00:00.000000 | 北京 | 不太行 |
| 20010053 | test20015002 | test20015002 | 2021-02-20 00:00:00.000000 | 廣州 | 不太行 |
| 20010054 | test20015003 | test20015003 | 2021-02-20 00:00:00.000000 | 深圳 | 不太行 |
| 20010055 | test20015004 | test20015004 | 2021-02-20 00:00:00.000000 | 廣州 | 不太行 |
| 20010056 | test20015005 | test20015005 | 2021-02-20 00:00:00.000000 | 廣州 | 不太行 |
| 20010057 | test20015006 | test20015006 | 2021-02-20 00:00:00.000000 | 深圳 | 不太行 |
| 20010058 | test20015007 | test20015007 | 2021-02-20 00:00:00.000000 | 廣州 | 不太行 |
+----------+--------------+--------------+----------------------------+------+---------+
10 rows in set (1 min 6.340 sec)
這次查詢需要1分6秒,很明顯當數據量過大時 查詢效率會直線下降 ,使用者毫無體驗(#-_-)
MariaDB [shoppings]> explain select u.num, u.name, u.nickname, u.settime, u.addr,c.content from login_userinfo as u inner join login_comment as c on u.comment_id=c.id limit 10000000, 10;
查看執行計划會看到它可能進行了全表掃描
MariaDB [shoppings]> explain select u.num, u.name, u.nickname, u.settime, u.addr,c.content from login_userinfo as u inner join login_comment as c on u.comment_id=c.id limit 10000000, 10;
+------+-------------+-------+-------+--------------------------------------------------------+--------------------------------------------------------+---------+----------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+--------------------------------------------------------+--------------------------------------------------------+---------+----------------+--------+-------------+
| 1 | SIMPLE | c | index | PRIMARY | content | 380 | NULL | 17 | Using index |
| 1 | SIMPLE | u | ref | Login_userinfo_comment_id_3d2eced3_fk_Login_comment_id | Login_userinfo_comment_id_3d2eced3_fk_Login_comment_id | 5 | shoppings.c.id | 681715 | |
+------+-------------+-------+-------+--------------------------------------------------------+--------------------------------------------------------+---------+----------------+--------+-------------+
2 rows in set (0.001 sec)
優化
查詢主鍵num值
MariaDB [shoppings]> select num from login_userinfo limit 10000000,1;
+----------+
| num |
+----------+
| 20010043 |
+----------+
1 row in set (3.259 sec)
MariaDB [shoppings]> explain select num from login_userinfo limit 10000000,1;
+------+-------------+----------------+-------+---------------+--------------------------------------------------------+---------+------+----------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------------+-------+---------------+--------------------------------------------------------+---------+------+----------+-------------+
| 1 | SIMPLE | login_userinfo | index | NULL | Login_userinfo_comment_id_3d2eced3_fk_Login_comment_id | 5 | NULL | 10907448 | Using index |
+------+-------------+----------------+-------+---------------+--------------------------------------------------------+---------+------+----------+-------------+
1 row in set (0.000 sec)
雖然我們也進行了全表掃描,但是我們用的是主鍵索引,所以效率會更高。
通過主鍵num值,查詢
MariaDB [shoppings]> select u.num, u.name, u.nickname, u.settime, u.addr,c.content from login_userinfo as u inner join login_comment as c on u.comment_id=c.id where u.num>20010043 limit 10;
+----------+--------------+--------------+----------------------------+------+---------+
| num | name | nickname | settime | addr | content |
+----------+--------------+--------------+----------------------------+------+---------+
| 20010045 | test20014994 | test20014994 | 2021-02-20 00:00:00.000000 | 深圳 | 不太行 |
| 20010046 | test20014995 | test20014995 | 2021-02-20 00:00:00.000000 | 廣州 | 不太行 |
| 20010047 | test20014996 | test20014996 | 2021-02-20 00:00:00.000000 | 北京 | 不太行 |
| 20010048 | test20014997 | test20014997 | 2021-02-20 00:00:00.000000 | 上海 | 不太行 |
| 20010049 | test20014998 | test20014998 | 2021-02-20 00:00:00.000000 | 深圳 | 不太行 |
| 20010050 | test20014999 | test20014999 | 2021-02-20 00:00:00.000000 | 北京 | 不太行 |
| 20010051 | test20015000 | test20015000 | 2021-02-20 00:00:00.000000 | 廣州 | 不太行 |
| 20010052 | test20015001 | test20015001 | 2021-02-20 00:00:00.000000 | 北京 | 不太行 |
| 20010053 | test20015002 | test20015002 | 2021-02-20 00:00:00.000000 | 廣州 | 不太行 |
| 20010054 | test20015003 | test20015003 | 2021-02-20 00:00:00.000000 | 深圳 | 不太行 |
+----------+--------------+--------------+----------------------------+------+---------+
10 rows in set (0.020 sec)
MariaDB [shoppings]> explain select u.num, u.name, u.nickname, u.settime, u.addr,c.content from login_userinfo as u inner join login_comment as c on u.comment_id=c.id where u.num>20010044 limit 10;
+------+-------------+-------+--------+----------------------------------------------------------------+---------+---------+------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+--------+----------------------------------------------------------------+---------+---------+------------------------+---------+-------------+
| 1 | SIMPLE | u | range | PRIMARY,Login_userinfo_comment_id_3d2eced3_fk_Login_comment_id | PRIMARY | 4 | NULL | 3638072 | Using where |
| 1 | SIMPLE | c | eq_ref | PRIMARY | PRIMARY | 4 | shoppings.u.comment_id | 1 | |
+------+-------------+-------+--------+----------------------------------------------------------------+---------+---------+------------------------+---------+-------------+
我們先拿到主鍵num的值 ,再通過num 進行查詢。通過這兩次查詢 時間不到4秒。效率大大提升。