一 SQL語句優(yōu)化的一般步驟:
創(chuàng)新互聯(lián)是專業(yè)的興隆臺網(wǎng)站建設(shè)公司,興隆臺接單;提供成都做網(wǎng)站、網(wǎng)站制作,網(wǎng)頁設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行興隆臺網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來合作!
1 通過show status命令了解各種SQL語句的執(zhí)行頻率
MySQL> show status; #show status:顯示服務(wù)器狀態(tài)信息
+-----------------------------------------------+-------------+
| Variable_name | Value |
+-----------------------------------------------+-------------+
| Aborted_clients | 0 |
| Aborted_connects | 0 |
| Binlog_cache_disk_use | 0 |
| Binlog_cache_use | 8 |
| Binlog_stmt_cache_disk_use | 0 |
| Binlog_stmt_cache_use | 25 |
| Bytes_received | 2919 |
| Bytes_sent | 51750 |
......
mysql> show status like "com%"; #顯示當(dāng)前session中,統(tǒng)計(jì)參數(shù)的值
+---------------------------+-------+
| Variable_name | Value |
+---------------------------+-------+
| Com_admin_commands | 0 |
| Com_assign_to_keycache | 0 |
| Com_alter_db | 0 |
| Com_alter_db_upgrade | 0 |
| Com_alter_event | 0 |
| Com_alter_function | 0 |
| Com_alter_procedure | 0 |
| Com_alter_server | 0 |
| Com_alter_table | 2 |
| Com_alter_tablespace | 0 |
| Com_alter_user | 0 |
| Com_analyze | 0 |
| Com_begin | 0 |
......
Com_xxx:表示每個(gè)xxx語句執(zhí)行的次數(shù),以下幾個(gè)統(tǒng)計(jì)參數(shù)非常重要:
Com_select:執(zhí)行select的次數(shù),一次查詢累計(jì)加1
Com_insert:執(zhí)行insert操作的次數(shù),批量插入只累加1
Com_delete:執(zhí)行delete操作的次數(shù),
Com_update:執(zhí)行update操作的次數(shù),
以上參數(shù)針對所有存儲引擎的表操作。
下面的參數(shù)是針對InnoDB存儲引擎的,算法也稍有不同:
Innodb_rows_read:select查詢返回的行數(shù)
Innodb_rows_inserted:執(zhí)行insert操作插入的行數(shù)
Innodb_rows_updated:執(zhí)行update操作更新的行數(shù)
Innodb_rows_deleted:執(zhí)行delete操作刪除的行數(shù)
通過以上參數(shù)的了解,可以判斷出當(dāng)前數(shù)據(jù)庫是以插入更新為主還是以查詢操作為主,以及各種類型SQL大致的執(zhí)行比例是多少。
此外,以下幾個(gè)參數(shù)可以幫助用戶了解數(shù)據(jù)庫的基本情況:
Uptime:數(shù)據(jù)庫服務(wù)器的工作時(shí)間
Connections:試圖連接服務(wù)器的次數(shù)
Slow_queries:慢查詢的次數(shù)
2 定位執(zhí)行效率低的SQL語句
方式1:通過慢查詢?nèi)罩径ㄎ?/p>
方式2:查看當(dāng)前正在進(jìn)行的線程
mysql> show processlist;
+----+-------------+-----------+------+---------+-------+-----------------------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------+------+---------+-------+-----------------------------------------------------------------------------+------------------+
| 1 | system user | | NULL | Connect | 34400 | Waiting for master to send event | NULL |
| 2 | system user | | NULL | Connect | 7738 | Slave has read all relay log; waiting for the slave I/O thread to update it | NULL |
| 4 | root | localhost | NULL | Query | 0 | init | show processlist |
或
[root@localhost ~]# mysqladmin -uroot -h 127.0.0.1 processlist -proot
Warning: Using a password on the command line interface can be insecure.
+----+------+-----------------+----+---------+------+-------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------------+----+---------+------+-------+------------------+
| 1 | root | localhost | | Sleep | 265 | | |
| 12 | root | localhost:42210 | | Query | 0 | init | show processlist |
+----+------+-----------------+----+---------+------+-------+------------------+
備注:show processlist;只列出前100條,如果想全列出請使用show full processlist;
3 通過explain分析低效的SQL語句的執(zhí)行
通過之前的步驟查詢到效率低的SQL語句之后,可以通過explain命令獲取MySQL是如何執(zhí)行select語句的信息。如:
mysql> explain select * from emp1;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | emp1 | ALL | NULL | NULL | NULL | NULL | 4 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
select_type——select類型
table——輸出結(jié)果的表
type——表示MySQL在表中找到所需行的方式,或者叫訪問類型,常見有以下幾種:性能由最差到最好。
type=all,即通過全表掃描找到匹配的行。
type=index,索引全掃描,mysql遍歷索引才找到匹配的行。
type=range,索引范圍掃描,
type=ref,使用非唯一索引掃描,或唯一索引的前綴掃描,返回匹配某個(gè)單獨(dú)值的記錄行
type=eq_ref,類似ref,區(qū)別在于使用的索引是唯一索引,對于每個(gè)索引鍵值,表中只有一條記錄匹配。
type=const/system,表單中最多有一個(gè)匹配行,查詢起來非常迅速。如根據(jù)主鍵和唯一索引進(jìn)行的查詢。
type=null,不需要訪問表或索引,直接就可以得到結(jié)果。
possible_keys——表示查詢時(shí)可能使用的索引
key——表示實(shí)際使用的索引
key_len——使用到索引字段的長度
rows——掃描行的數(shù)量
Extra——執(zhí)行情況的說明和描述
4 通過show profile了解分析SQL執(zhí)行的過程
mysql> select @@have_profiling; #查看是否支持
+------------------+
| @@have_profiling |
+------------------+
| YES |
+------------------+
mysql> set profiling=1; #開啟profiling,默認(rèn)是關(guān)閉
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> select * from emp1; #執(zhí)行一個(gè)語句
+------+--------+-------+------------+
| age1 | deptno | ename | birth |
+------+--------+-------+------------+
| 111 | 4 | ccc | 2011-11-30 |
| 666 | 11 | ddd | 2014-12-22 |
| 888 | 22 | eee | 2015-11-30 |
| 333 | 8 | fff | 2011-04-30 |
+------+--------+-------+------------+
4 rows in set (0.02 sec)
mysql> show profiles; #查看當(dāng)前SQL語句的查詢ID
+----------+------------+---------------------------+
| Query_ID | Duration | Query |
+----------+------------+---------------------------+
| 1 | 0.01696625 | select count(*) from emp1 |
| 2 | 0.02623125 | select * from emp1 |
+----------+------------+---------------------------+
mysql> show profile for query 2; #查看執(zhí)行過程中線程的每個(gè)狀態(tài)和消耗時(shí)間
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000111 |
| checking permissions | 0.000019 |
| Opening tables | 0.000046 |
| init | 0.000043 |
| System lock | 0.000031 |
| optimizing | 0.000016 |
| statistics | 0.000039 |
| preparing | 0.000023 |
| executing | 0.000008 |
| Sending data | 0.025442 |
| end | 0.000020 |
| query end | 0.000014 |
| closing tables | 0.000016 |
| freeing items | 0.000326 |
| cleaning up | 0.000079 |
+----------------------+----------+
Sending data表示MySQL線程開始訪問數(shù)據(jù)行并把結(jié)果返回給客戶端。通常是整個(gè)查詢中耗時(shí)最長的狀態(tài)
mysql> show profile cpu for query 2; #查看耗費(fèi)CPU的時(shí)間,Sending data主要耗費(fèi)在CPU上
+----------------------+----------+----------+------------+
| Status | Duration | CPU_user | CPU_system |
+----------------------+----------+----------+------------+
| starting | 0.000111 | 0.000000 | 0.000000 |
| checking permissions | 0.000019 | 0.000000 | 0.000000 |
| Opening tables | 0.000046 | 0.000000 | 0.000000 |
| init | 0.000043 | 0.000000 | 0.000000 |
| System lock | 0.000031 | 0.000000 | 0.000000 |
| optimizing | 0.000016 | 0.000000 | 0.000000 |
| statistics | 0.000039 | 0.000000 | 0.000000 |
| preparing | 0.000023 | 0.000000 | 0.000000 |
| executing | 0.000008 | 0.000000 | 0.000000 |
| Sending data | 0.025442 | 0.000000 | 0.001999 |
| end | 0.000020 | 0.000000 | 0.000000 |
| query end | 0.000014 | 0.000000 | 0.000000 |
| closing tables | 0.000016 | 0.000000 | 0.000000 |
| freeing items | 0.000326 | 0.000000 | 0.000000 |
| cleaning up | 0.000079 | 0.000000 | 0.000000 |
+----------------------+----------+----------+------------+
mysql> show profile all for query 1\G #查看所有明細(xì),了解MySQL在什么資源上耗費(fèi)了過高的時(shí)間
5 通過trace分析優(yōu)化器如何選擇執(zhí)行計(jì)劃
6 確定問題之后,采取相應(yīng)的措施優(yōu)化
由前面的步驟確認(rèn)對表進(jìn)行全表掃描,導(dǎo)致查詢效果不理想,那么對表的某個(gè)字段建立索引。具體如下 :
mysql> create index index_ename on emp1(ename);
Query OK, 0 rows affected (0.25 sec)
Records: 0 Duplicates: 0 Warnings: 0
建立索引后,再看下這條語句的執(zhí)行狀態(tài):
mysql> explain select ename from emp1;
建立索引后,可以發(fā)現(xiàn)對表掃描的行數(shù)大大減少,提高了對表的訪問速度。
二 索引問題
索引是數(shù)據(jù)庫優(yōu)化中最重要也是最常用的手段之一,通過索引可以幫助用戶解決大多數(shù)SQL性能問題。
1 索引的存儲分類:索引是在存儲引擎層中實(shí)現(xiàn)的
B-Tree索引:最常見的索引,大部分引擎支持B樹索引。
HASH索引:只有Memory引擎支持,使用場景簡單
Full-text(全文索引):一種特殊索引類型
創(chuàng)建索引方式 1:
mysql> create index index_age1 on emp1(age1);
Query OK, 0 rows affected (0.15 sec)
Records: 0 Duplicates: 0 Warnings: 0
創(chuàng)建索引方式 2:
mysql> alter table zwj.emp1 add index index_ename (ename);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
查看索引:
mysql> show index from zwj.emp1;
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| emp1 | 1 | index_ename | 1 | ename | A | 4 | NULL | NULL | YES | BTREE | | |
| emp1 | 1 | index_age1 | 1 | age1 | A | 4 | NULL | NULL | YES | BTREE | | |
+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
刪除索引:
mysql> drop index index_age1 on zwj.emp1;
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
或
mysql> alter table zwj.emp1 drop index index_ename;
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0
另有復(fù)合索引:需要咨詢開發(fā)人員
創(chuàng)建復(fù)合索引(將最常用作限制條件的列放在最左邊,依次遞減):
mysql> create index name_passwd on abc.student(name,passwd);(需要咨詢研發(fā)部門)
2 查看索引的使用情況:
mysql> show status like 'handler_read%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| Handler_read_first | 4 |
| Handler_read_key | 5 |
| Handler_read_last | 0 |
| Handler_read_next | 0 |
| Handler_read_prev | 0 |
| Handler_read_rnd | 0 |
| Handler_read_rnd_next | 56 |
+-----------------------+-------+
7 rows in set (0.00 sec)
Handler_read_key:如果索引正在工作,此值應(yīng)該很高,這個(gè)值代表了一個(gè)行被索引值讀的次數(shù)。如果值過低,表明增加索引得到的性能改善不高,因?yàn)樗饕⒉怀1皇褂谩?/p>
Handler_read_rnd_next:值高意味著查詢運(yùn)行低效,并且應(yīng)該建立索引補(bǔ)救。這個(gè)值的含義是在數(shù)據(jù)文件中讀下一行的請求數(shù)。如果進(jìn)行了大量的掃描,它的值會很高,說明索引不正確或查詢沒有利用到索引。