MySQL監控調優
一、Mysql性能介紹
1、什么是Mysql?它有什么優點?
MySQL是一個關系型數據庫管理系統,由瑞典MySQL AB公司開發,目前屬於Oracle公司。MySQL是一種關聯數據庫管理系統,關聯數據庫將數據保存在不同的表中,而不是將所有數據放在一個大倉庫內,這樣就增加了速度並提高了靈活性。
- Mysql是開源的,所以你不需要支付額外的費用。
- Mysql支持大型的數據庫。可以處理擁有上千萬條記錄的大型數據庫。
- MySQL使用標准的SQL數據語言形式。
- Mysql可以允許於多個系統上,並且支持多種語言。這些編程語言包括C、C++、Python、Java、Perl、PHP、Eiffel、Ruby和Tcl等。
- Mysql對PHP有很好的支持,PHP是目前最流行的Web開發語言。
- MySQL支持大型數據庫,支持5000萬條記錄的數據倉庫,32位系統表文件最大可支持4GB,64位系統支持最大的表文件為8TB。
- Mysql是可以定制的,采用了GPL協議,可以修改源碼來開發自己的Mysql系統。
影響Mysql性能的原因總結一下 主要在下面這幾點
- 服務器硬件
- 網卡流量
- 磁盤IO
- SQL查詢速度
服務器硬件
1
2
3
4
5
6
7
8
9
|
CPU:
64位的CPU一定要工作在64位的系統下
對於並發比較高的 場景,CPU的數量比頻率重要
對於密集型場景和復雜SQL,則CPU頻率越高越好
內存:
選擇主板所能使用的最高頻率的內存
內存的大小對於性能很重要,所以盡可能的大
I/O子系統:
PCIe -> SSD ->Raid10 ->磁盤 ->SAN
|
2、Mysql的查詢過程

3、Mysql架構
DDL (Data Definition Language 數據定義語言)
1
2
3
4
5
6
|
create table 創建表
alter table 修改表
drop table 刪除表
truncate table 刪除表中所有行
create index 創建索引
drop index 刪除索引
|
DML (Data Manipulation Language 數據操作語言)
1
2
3
|
insert 將記錄插入到數據庫
update 修改數據庫的記錄
delete 刪除數據庫的記錄
|
4、Mysql連接數
MYSQL數據庫默認最大連接數是100,然而對於流量稍微大一點的論壇或網站這個連接數是遠遠不夠的,當並發數過大的時候會出現連接數不夠用,使得很多線程在等待其他連接釋放,會直接導致導致數據庫連接超時或者響應時間過長,所以需要調整最大連接數。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
# 重新設置數據庫最大連接數
set global max_connections=1000
# 查詢數據庫當前設置的最大連接數
show variables like '%max_connections%';
MariaDB
[(none)]> show variables like '%max_connections%';
+-----------------------+-------+
|
Variable_name | Value |
+-----------------------+-------+
|
extra_max_connections | 1 | # extra_port可以接受的最大連接數
|
max_connections | 151 | # 最大連接數
+-----------------------+-------+
2
rows in set (0.00 sec)
# extra_port是之前5.6版本開始新增的,指定了可以使用的端口
# 服務器響應的最大連接數
show global status like 'Max_used_connections';
MariaDB
[(none)]> show global status like 'Max_used_connections';
+----------------------+-------+
|
Variable_name | Value |
+----------------------+-------+
|
Max_used_connections | 4 |
+----------------------+-------+
1
row in set (0.00 sec)
# 服務器線程方面的
show status like 'Threads%';
MariaDB
[(none)]> show status like 'Threads%';
+-------------------+-------+
|
Variable_name | Value |
+-------------------+-------+
|
Threads_cached | 0 | # mysql管理的線程池中還有多少可以被復用的資源
|
Threads_connected | 3 | # 打開的連接數
|
Threads_created | 226 | # 表示創建過的線程數
|
Threads_running | 1 | # 激活的連接數,這個數值一般遠低於connected數值,
# 准確的來說,Threads_running是代表當前並發數
+-------------------+-------+
4
rows in set (0.00 sec)
|
5、Mysql緩存
數據庫屬於 IO 密集型的應用程序,其主要職責就是數據的管理及存儲工作。而我們知道,從內存中讀取一個數據庫的時間是微秒級別,而從一塊普通硬盤上讀取一個IO是在毫秒級別,二者相差3個數量級。所以,要優化數據庫,首先第一步需要優化的就是 IO,盡可能將磁盤IO轉化為內存IO。
緩存分為兩個維度,查詢緩存Query cache和存儲引擎InnoDB_Buffer_Pool
- 查詢緩存Query cache
查詢緩存會緩存完整的SELECT查詢結果,當查詢命中緩存時MySQL會將結果立刻返回,直接跳過了解析、優化和執行階段。
當然,Query Cache 也有一個致命的缺陷,那就是當某個表的數據有任何任何變化,都會導致所有引用了該表的select語句在Query Cache 中的緩存數據失效。所以,當我們的數據變化非常頻繁的情況下,使用Query Cache 可能會得不償失。
因此,應用程序不需要關心MySQL是通過緩存查詢出的結果還是實際執行過SQL語句返回的結果,因為這兩種結果是完全相同的。
從前面的數據庫執行過程圖中可以看到,執行一條SQL查詢語句會先查詢該語句是否存在於緩存中,需要注意的是當語句中的字符大小寫或注釋只要有一點點的不同,查詢緩存就會被認為是不同的查詢,導致無法命中查詢緩存。另外,對於不確定的函數,如:now()、current_date()等這種查詢都不會被緩存。
既然查詢緩存的有可以改善性能的優點,自然也有自己的缺點,主要體現在當開啟了查詢緩存時對於讀寫操作都增加了額外的開銷。相對於讀,再查詢開始前需要先檢查緩存,而對於寫,則是當寫入數據后需要更新緩存。
- Query cache的參數:
查詢緩存參數,在mysql配置文件中添加,linux下為my.cnf,windows下為my.ini:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# 1.是否開啟查詢緩存,具體選項是off,on
query_cache_type = on
# 2.分配給查詢緩存的總內存,一般建議不超過256M
query_cache_size = 200M
# 3.這個選項限制了MySQL存儲的最大結果。如果查詢的結果比這個大,那么就不會被緩存。
query_cache_limit = 1M
# 查詢qcache狀態:
MariaDB [(none)]> show variables like '%query_cache%';
+------------------------------+---------+
| Variable_name | Value |
+------------------------------+---------+
| have_query_cache | YES | #該MySQL 是否支持Query Cache
| query_cache_limit | 1048576 | #緩存塊大小,超過該大小不會被緩存
| query_cache_min_res_unit | 4096 | #每個qcache最小的緩存空間大小
| query_cache_size | 1048576 | #分配給查詢緩存的總內存
| query_cache_strip_comments | OFF | #用於控制QC中是否去掉SQL語句的注釋部分。
| query_cache_type | OFF | #是否開啟
| query_cache_wlock_invalidate | OFF | #控制當有鎖加在表上的時候,是否先讓該表相關的緩存失效
+------------------------------+---------+
7 rows in set (0.00 sec)
|
修改完配置后,讓我們再來監控Qcache的使用情況。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# 查詢qcache當前使用情況:
SHOW STATUS LIKE 'Qcache%';
MariaDB [(none)]> show status like 'Qcache%';
+-------------------------+---------+
| Variable_name | Value |
+-------------------------+---------+
| Qcache_free_blocks | 1 | # 表示查詢緩存中處以重現狀態的內存塊數(碎片數量)。如果
# Qcache_free_blocks 的值較大,則意味着查詢緩存中碎片比較多
# 表明查詢結果集較小,此時可以減小query_cache_min_res_unit
# 使用flush query cache 會對緩存中的若干個碎片進行整理,從
# 而得到一個比較大的空閑塊。
| Qcache_free_memory | 1031336 | # Query Cache 中目前剩余的內存大小
| Qcache_hits | 0 | # 緩存命中次數
| Qcache_inserts | 0 | # 多少次未命中然后插入
| Qcache_lowmem_prunes | 0 | # 因為查詢緩存已滿而溢出,導致MySQL刪除的查詢結果個數。
# 如果該值比較大,則表明查詢緩存過小。
| Qcache_not_cached | 0 | # 沒有進入查詢緩存的select個數
| Qcache_queries_in_cache | 0 | # 查詢緩存中緩存中有多少條select語句的結果集
| Qcache_total_blocks | 1 | # 查詢緩存的總個數
+-------------------------+---------+
8 rows in set (0.00 sec)
Query Cache 命中率= Qcache_hits / ( Qcache_hits + Qcache_inserts );
|
- 存儲引擎層-innodb buffer pool
buffer pool是innodb存儲引擎帶的一個緩存池,查詢數據的時候,它首先會從內存中查詢,如果內存中存在的話,直接返回,從而提高查詢響應時間。
innodb buffer pool和qcache的區別是:qcacche緩存的是sql語句對應的結果集,buffer pool中緩存的是表中的數據。Buffer pool是設置的越大越好,一般設置為服務器物理內存的70%。
1
2
3
4
5
|
innodb_buffer_pool_size = 16M # Innodb_buffer_pool的大小
innodb_buffer_pool_dump_now: 默認為關閉OFF。如果開啟該參數,停止MySQL服務時,InnoDB將InnoDB緩沖池中的熱數據保存到本地硬盤。
innodb_buffer_pool_load_at_startup:默認為關閉OFF。如果開啟該參數,啟動MySQL服務時,MySQL將本地熱數據加載到InnoDB緩沖池中。
|
- 查看Innodb_buffer_pool狀態
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
查詢
Innodb_buffer_pool狀態:
SHOW VARIABLES LIKE '%innodb_buffer_pool%';
MariaDB [(none)]> SHOW VARIABLES LIKE '%innodb_buffer_pool%';
+-------------------------------------+----------------+
| Variable_name | Value |
+-------------------------------------+----------------+
| innodb_buffer_pool_dump_at_shutdown | OFF | ##停止mysq服務時是否自動保存熱數據
| innodb_buffer_pool_dump_now | OFF | ##啟動mysql服務時是否自動讀取熱數據
| innodb_buffer_pool_dump_pct | 100 | #表示轉儲每個bp instance LRU上最熱的page的百分比。
| innodb_buffer_pool_filename | ib_buffer_pool | #熱數據文件名稱
| innodb_buffer_pool_instances | 8 | # 表示InnoDB緩存池被划分到多少個區域
| innodb_buffer_pool_load_abort | OFF | # 立刻中斷LOAD操作
| innodb_buffer_pool_load_at_startup | OFF | # 啟動實例時讀入轉儲文件中記錄的Page
| innodb_buffer_pool_load_now | OFF | # 立即做一次轉儲文件讀入
| innodb_buffer_pool_populate | OFF |
| innodb_buffer_pool_size | 16777216 | ##設置的bp大小
+-------------------------------------+----------------+
10 rows in set (0.01 sec)
|
- 監控Innodb_buffer_pool使用情況
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
查詢
Innodb_buffer_pool當前使用情況:
SHOW STATUS LIKE '%Innodb_buffer_pool%';
MariaDB [(none)]> SHOW STATUS LIKE '%Innodb_buffer_pool%';
+-----------------------------------------+----------------------------------------+
| Variable_name | Value |
+-----------------------------------------+----------------------------------------+
| Innodb_buffer_pool_bytes_data | 4194304 |
| Innodb_buffer_pool_bytes_dirty | 0 |
| Innodb_buffer_pool_dump_status | Dumping buffer pool(s) not yet started |
| Innodb_buffer_pool_load_status | Loading buffer pool(s) not yet started |
| Innodb_buffer_pool_pages_data | 256 |
| Innodb_buffer_pool_pages_dirty | 0 |
| Innodb_buffer_pool_pages_flushed | 6186 |
| Innodb_buffer_pool_pages_free | 765 |
| Innodb_buffer_pool_pages_lru_flushed | 0 |
| Innodb_buffer_pool_pages_made_not_young | 4584 |
| Innodb_buffer_pool_pages_made_young | 0 |
| Innodb_buffer_pool_pages_misc | 2 |
| Innodb_buffer_pool_pages_old | 0 |
| Innodb_buffer_pool_pages_total | 1023 |
| Innodb_buffer_pool_read_ahead | 831 |
| Innodb_buffer_pool_read_ahead_evicted | 0 |
| Innodb_buffer_pool_read_ahead_rnd | 0 |
| Innodb_buffer_pool_read_requests | 1758225 |
| Innodb_buffer_pool_reads | 8144 |
| Innodb_buffer_pool_wait_free | 0 |
| Innodb_buffer_pool_write_requests | 13403 |
+-----------------------------------------+----------------------------------------+
21 rows in set (0.00 sec)
主要關注的兩個參數
innodb_buffer_pool_read_requests 總共查詢bp的次數
innodb_buffer_pool_reads 從物理磁盤中獲取到數據的次數
|
6、事務和鎖
事務就是一組原子性的SQL查詢,或者也可以說一個獨立的工作單元。如果數據庫引擎可以成功的對數據庫應用該組查詢的全部語句,那么就執行該組查詢。如果其中任意一條語句因為某種原因無法執行,那么其他的語句都不會執行。也就是說,事務內的語句要么全部都執行,要么全部執行失敗。
- 表級鎖和行級鎖
行級鎖又分共享鎖和排他鎖。
共享鎖:共享鎖又叫做讀鎖,所有的事務只能對其進行讀操作不能寫操作,加上共享鎖后在事務結束之前其他事務只能再加共享鎖,除此之外其他任何類型的鎖都不能再加了。
1
|
SELECT `Id` FROM Score WHERE Id in (1,2); <span style="color: #ff0000;">LOCK IN SHARE MODE</span> 結果集的數據都會加共享鎖
|
排他鎖:若某個事物對某一行加上了排他鎖,只能這個事務對其進行讀寫,在此事務結束之前,其他事務不能對其進行加任何鎖,其他進程可以讀取,不能進行寫操作,需等待其釋放。for update僅適用於InnoDB,且必須在事務塊(BEGIN/COMMIT)中才能生效。在進行事務操作時,通過“for update”語句,MySQL會對查詢結果集中每行數據都添加排他鎖,其他線程對該記錄的更新與刪除操作都會阻塞。
1
|
SELECT `Id` FROM Score WHERE Id=1 FOR UPDATE
|
表級鎖是MySQL中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現簡單,資源消耗較少,被大部分MySQL引擎支持。最常使用的MYISAM與INNODB都支持表級鎖定。表級鎖定分為表共享讀鎖(共享鎖)與表獨占寫鎖(排他鎖)。
特點
開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發出鎖沖突的概率最高,並發度最低。
- 死鎖
我們在測試中經常會遇到數據庫死鎖的情況,那么什么是死鎖呢? 死鎖是指兩個或者多個事務在同一資源上互相占用,並且請求鎖定對方占用的資源,從而導致惡性循環的現象。
1
2
3
4
5
6
7
8
9
10
11
12
|
事務1:
START TRANSACTION;
UPDATE score set grade = 95 where id = 5;
UPDATE score set grade = 87 where id = 6;
COMMIT;
事務2:
START TRANSACTION;
UPDATE score set grade = 78 where id = 6;
UPDATE score set grade = 85 where id = 5;
COMMIT;
|
當兩個事務同時執行,每個事務都執行了第一條update語句,更新了一行數據的同時也會鎖定該行數據,接下來每個事務會嘗試去執行第二條update語句,在這時會發現要修改的這條數據已經被鎖定了,然后兩個事務都在互相等待對方釋放鎖,同時又都持有對方所需要的鎖,在這樣的情況下就陷入了死循環。也就是死鎖了,對於出現死鎖的情況下,只有通過外部因素來介入來解除死鎖。
當然既然存在有死鎖的情況,自然也就有一些解決問題的方法,數據庫系統實現了各種死鎖檢測和死鎖超時機制。比如InnoDB存儲引擎,就能檢測到死鎖的循環依賴,並且立即會返回一個錯誤。
鎖的行為和順序是和存儲引擎相關的,以同樣的順序去執行語句時,有些存儲引擎會出現死鎖,有些就不會。因此死鎖的產生有雙重原因,有些是因為真正的數據沖突,有些則是因為存儲引擎的實現方式導致。
如何查看死鎖呢?
1
2
3
4
5
6
7
|
查看是否死鎖:
show engine innodb status;(一般日志里有dblock、lock等字樣)
SELECT * FROM information_schema.INNODB_TRX; (定位哪個線程導致死鎖)
show processlist;
KILL xxxx;
|
- 多線程並發才有可能死鎖
- 避免交叉加鎖
- 減少涉及的表,表聯接會大大增加鎖范圍
- 避免全表更新,控制更新行數
二、Mysql慢查詢
開啟慢查詢日志,可以讓MySQL記錄下查詢超過指定時間的語句,通過定位分析性能的瓶頸,才能更好的優化數據庫系統的性能。顧名思義,慢查詢日志中記錄的是執行時間較長的query,也就是我們常說的slowquery,通過設–log-slow-queries[=file_name]來打開該功能並設置記錄位置和文件名。
慢查詢日志采用的是簡單的文本格式,可以通過各種文本編輯器查看其中的內容。其中記錄了語句執行的時刻,執行所消耗的時間,執行用戶,連接主機等相關信息。MySQL 還提供了專門用來分析滿查詢日志的工具程序mysqlslowdump,用來幫助數據庫管理人員解決可能存在的性能問題。
- 查看慢查詢相關參數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
MariaDB
[(none)]> show variables like 'slow_query%';
+---------------------+---------------+
|
Variable_name | Value |
+---------------------+---------------+
|
slow_query_log | OFF |
|
slow_query_log_file | liml-slow.log |
+---------------------+---------------+
2
rows in set (0.00 sec)
MariaDB
[(none)]> show variables like 'long_query_time';
+-----------------+-----------+
|
Variable_name | Value |
+-----------------+-----------+
|
long_query_time | 10.000000 |
+-----------------+-----------+
1
row in set (0.00 sec)
slow_query_log
慢查詢開啟狀態
slow_query_log_file
慢查詢日志存放的位置(這個目錄需要MySQL的運行帳號的可寫權限,一般設置為MySQL的數據存放目錄)
long_query_time
查詢超過多少秒才記錄,默認為10秒
|
- 配置Mysql慢查詢(通過配置文件)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Linux:
在mysql配置文件my.cnf中增加:
[mysqld]
slow_query_log
= ON
slow_query_log_file
= /opt/logs/slow.log
long_query_time
=2
Windows:
在my.ini的[mysqld]添加如下語句:
log-slow-queries = E:\web\mysql\log\mysqlslowquery.loglong_query_time = 2
(其他參數如上)
slow_query_log_file
(指定日志文件存放位置,可以為空,系統會給一個缺省的文件host_name-slow.log)
long_query_time(記錄超過的時間,默認為10s)
slow_query_log
記錄慢查詢日志開關
|
- 使用命令啟動MySQL慢查詢
1
2
3
4
5
6
7
8
|
將
slow_query_log 全局變量設置為“ON”狀態
mysql
> set global slow_query_log='ON';
設置慢查詢日志存放的位置
mysql
> set global slow_query_log_file='/opt/slow.log';
查詢超過1秒就記錄
mysql
> set global long_query_time=1;
|
- Mysqldumpslow命令
1
2
3
4
5
6
|
mysqldumpslow
-s c -t 10 /database/mysql/slow-log
#這會輸出記錄次數最多的10條SQL語句,其中:
-s,
是表示按照何種方式排序,c、t、l、r分別是按照記錄次數、時間、查詢時間、返回的記錄數來排序,ac、at、al、ar,表示相應的倒敘;
-t,
是top n的意思,即為返回前面多少條的數據;
-g,
后邊可以寫一個正則匹配模式,大小寫不敏感的;
|
- explain
前面分析出了具體是哪一條SQL導致的查詢速度過慢,那么我們該如何針對這些占用資源嚴重的SQL來進一步的分析呢??答案就是使用explain
Explain :該命令是查看查詢優化器如何決定執行查詢的主要方法,這個功能有局限性,只是一個近似結果,有時它是一個很好的近似,有時可能相差甚遠。但它的輸出是可以獲取的最准確信息,值得仔細學習。使用方法如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
MariaDB
[besttest]> select * from students where id in (801,802,803);
+-----+-----------+------+------+--------+--------------------+
|
Id | Name | Sex | age | class | Addr |
+-----+-----------+------+------+--------+--------------------+
|
801 | 安大叔 | 男 | 20 | besttest| 北京市海淀區 |
|
802 | 小胖子 | 男 | 38 | besttest| 北京市昌平區 |
|
803 | 小楠楠 | 男 | 18 | besttest| 湖南省永州市 |
+-----+-----------+------+------+--------+--------------------+
3
rows in set (0.00 sec)
MariaDB
[besttest]> explain select * from students where id in (801,802,803);
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
|
1 | SIMPLE | students | range | PRIMARY | PRIMARY | 4 | NULL | 3 | Using where |
+------+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
1
row in set (0.00 sec)
|
explain的列:
我們先完成一個建表
1
2
3
|
CREATE TABLE `t1` (`id` int NOT NULL AUTO_INCREMENT ,`name` varchar(255) NULL ,`age` INT(3) NULL,PRIMARY KEY (`id`));
CREATE TABLE `t2` (`id` int NOT NULL AUTO_INCREMENT ,`name` varchar(255) NULL ,`age` INT(3) NULL,PRIMARY KEY (`id`));
CREATE TABLE `t3` (`id` int NOT NULL AUTO_INCREMENT ,`name` varchar(255) NULL ,`age` INT(3) NULL,PRIMARY KEY (`id`));
|
1. id:
包含一組數字,表示查詢中執行select子句或操作表的順序(id相同,執行順序由上至下),如果是子查詢,id值越大優先級越高,越先被執行
1
2
3
4
5
6
7
8
9
10
11
12
|
explain select t2.* from t2 where id =
(
select id from t1 where id = (select t3.id from t3 where t3.name=''));
MariaDB
[besttest]> explain select t2.* from t2 where id = (select id from t1 where id = (select t3.id from t3 where t3.name=''));
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|
1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables |
|
2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | no matching row in const table |
|
3 | SUBQUERY | t3 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
3
rows in set (0.00 sec)
|
如果ID相同,則按照順序從上向下
1
2
3
4
5
6
7
8
|
MariaDB
[besttest]> explain select t2.* from (select t3.id from t3 where t3.name='')s1, t2 where s1.id=t2.id;
+------+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
|
1 | SIMPLE | t3 | ALL | PRIMARY | NULL | NULL | NULL | 1 | Using where |
|
1 | SIMPLE | t2 | eq_ref | PRIMARY | PRIMARY | 4 | besttest.t3.id | 1 | |
+------+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
2
rows in set (0.00 sec)
|
2. select_type
示查詢中每個select子句的類型(簡單OR復雜)
- SIMPLE:查詢中不包含子查詢或者UNION
- 查詢中若包含任何復雜的子部分,最外層查詢則被標記為:PRIMARY
- 在SELECT或WHERE列表中包含了子查詢,該子查詢被標記為:SUBQUERY
- 在FROM列表中包含的子查詢被標記為:DERIVED(衍生)用來表示包含在from子句中的子查詢的selectmysql會遞歸執行並將結果放到一個臨時表中。服務器內部稱為”派生表”,因為該臨時表是從子查詢中派生出來的
- 若第二個SELECT出現在UNION之后,則被標記為UNION;若UNION包含在FROM子句的子查詢中,外層SELECT將被標記為:DERIVED
- 從UNION表獲取結果的SELECT被標記為:UNION RESULT
SUBQUERY和UNION還可以被標記為DEPENDENT和UNCACHEABLE。
DEPENDENT意味着select依賴於外層查詢中發現的數據。
UNCACHEABLE意味着select中的某些 特性阻止結果被緩存於一個item_cache中。
1
2
3
4
5
6
7
8
9
10
|
MariaDB
[besttest]> explain select d1.name, ( select id from t3) d2 from (select id,name from t1 where name='')d1 union (select name,id from t2);
+------+--------------+------------+-------+---------------+---------+---------+------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+--------------+------------+-------+---------------+---------+---------+------+------+-------------+
|
1 | PRIMARY | t1 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
|
2 | SUBQUERY | t3 | index | NULL | PRIMARY | 4 | NULL | 1 | Using index |
|
4 | UNION | t2 | ALL | NULL | NULL | NULL | NULL | 1 | |
|
NULL | UNION RESULT | <union1,4> | ALL | NULL | NULL | NULL | NULL | NULL | |
+------+--------------+------------+-------+---------------+---------+---------+------+------+-------------+
4
rows in set (0.00 sec)
|
3. type
表示MySQL在表中找到所需行的方式,又稱“訪問類型”,常見類型如下:
ALL, index, range, ref, eq_ref, const, system, NULL
從左到右,性能從最差到最好
ALL:Full Table Scan, MySQL將遍歷全表以找到匹配的行
1
2
3
4
5
6
7
|
MariaDB
[besttest]> explain select * from t1 where name='';
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
|
1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
1
row in set (0.00 sec)
|
index:Full Index Scan,index與ALL區別為index類型只遍歷索引樹
1
2
3
4
5
6
7
|
MariaDB
[besttest]> explain select id from t1;
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|
1 | SIMPLE | t1 | index | NULL | PRIMARY | 4 | NULL | 1 | Using index |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1
row in set (0.00 sec)
|
range:索引范圍掃描,對索引的掃描開始於某一點,返回匹配值域的行。索引范圍掃描是帶有between或者where子句里帶有<, >查詢。當mysql使用索引去查找一系列值時,例如IN()和OR列表,也會顯示range(范圍掃描),當然性能上面是有差異的。
1
2
3
4
5
6
7
|
MariaDB
[besttest]> explain select * from t1 where id in (2,6);
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|
1 | SIMPLE | t1 | range | PRIMARY | PRIMARY | 4 | NULL | 2 | Using where |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1
row in set (0.00 sec)
|
ref:使用非唯一索引掃描或者唯一索引的前綴掃描,返回匹配某個單獨值的記錄行
1
2
3
4
5
6
7
|
MariaDB
[besttest]> explain select * from t1 where name = 'zhang';
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
|
1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
1
row in set (0.00 sec)
|
eq_ref類似ref,區別就在使用的索引是唯一索引,對於每個索引鍵值,表中只有一條記錄匹配,簡單來說,就是多表連接中使用primary key或者 unique key作為關聯條件
1
2
3
4
5
6
7
8
|
MariaDB
[besttest]> explain select t1.name from t1, t2 where t1.id=t2.id;
+------+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
|
1 | SIMPLE | t1 | ALL | PRIMARY | NULL | NULL | NULL | 1 | |
|
1 | SIMPLE | t2 | eq_ref | PRIMARY | PRIMARY | 4 | besttest.t1.id | 1 | Using index |
+------+-------------+-------+--------+---------------+---------+---------+----------------+------+-------------+
2
rows in set (0.00 sec)
|
const,system,當MySQL對查詢某部分進行優化,並轉換為一個常量時,使用這些類型訪問。如將主鍵置於where列表中,MySQL就能將該查詢轉換為一個常量。
1
2
3
4
5
6
7
|
MariaDB
[besttest]> explain select * from ( select * from t1 where id=1) b;
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|
1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables |
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
1
row in set (0.00 sec)
|
NULL,MySQL在優化過程中分解語句,執行時甚至不用訪問表或索引,例如從一個索引列里選取最小值可以通過單獨索引查找完成。
1
2
3
4
5
6
7
8
|
MariaDB
[besttest]> explain select * from t1 where id = (select min(id) from t2);
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|
1 | PRIMARY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE noticed after reading const tables |
|
2 | SUBQUERY | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No matching min/max row |
+------+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
2
rows in set (0.00 sec)
|
4. possible_keys
指出MySQL能使用哪個索引在表中找到記錄,查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢使用
5. key
顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示為NULL
6. key_len
表示索引中使用的字節數,可通過該列計算查詢中使用的索引的長度(key_len顯示的值為索引字段的最大可能長度,並非實際使用長度,即key_len是根據表定義計算而得,不是通過表內檢索出的)
7. ref
表示上述表的連接匹配條件,即哪些列或常量被用於查找索引列上的值
8. rows
表示MySQL根據表統計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數
9. Extra
包含不適合在其他列中顯示但十分重要的額外信息
a. Using index
該值表示相應的select操作中使用了覆蓋索引(Covering Index)
1
2
3
4
5
6
7
|
MariaDB
[besttest]> explain select id from t1;
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
|
1 | SIMPLE | t1 | index | NULL | PRIMARY | 4 | NULL | 1 | Using index |
+------+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1
row in set (0.00 sec)
|
b. Using where
表示mysql服務器將在存儲引擎檢索行后再進行過濾。許多where條件里涉及索引中的列,當(並且如果)它讀取索引時,就能被存儲引擎檢驗,因此不是所有帶where字句的查詢都會顯示”Using where”。有時”Using where”的出現就是一個暗示:查詢可受益與不同的索引。
1
2
3
4
5
6
7
|
MariaDB [besttest]> explain select * from t1 where name = 'zhang';
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 1 | Using where |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
|
c. Using temporary
表示MySQL需要使用臨時表來存儲結果集,常見於排序和分組查詢
這個值表示使用了內部臨時(基於內存的)表。一個查詢可能用到多個臨時表。有很多原因都會導致MySQL在執行查詢期間創建臨時表。兩個常見的原因是在來自不同表的上使用了DISTINCT,或者使用了不同的ORDER BY和GROUP BY列。可以強制指定一個臨時表使用基於磁盤的MyISAM存儲引擎。這樣做的原因主要有兩個:
1)內部臨時表占用的空間超過min(tmp_table_size,max_heap_table_size)系統變量的限制
2)使用了TEXT/BLOB 列
1
2
3
4
5
6
7
|
MariaDB
[besttest]> explain select id from t1 where id in (1,2) group by age,name;
+------+-------------+-------+-------+---------------+---------+---------+------+------+----------------------------------------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+-------+---------------+---------+---------+------+------+----------------------------------------------+
|
1 | SIMPLE | t1 | range | PRIMARY | PRIMARY | 4 | NULL | 2 | Using where; Using temporary; Using filesort |
+------+-------------+-------+-------+---------------+---------+---------+------+------+----------------------------------------------+
1
row in set (0.00 sec)
|
d. Using filesort
MySQL中無法利用索引完成的排序操作稱為“文件排序”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
MariaDB
[besttest]> explain select id,age from t1 order by name;
+------+-------------+-------+------+---------------+------+---------+------+------+----------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+----------------+
|
1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 1 | Using filesort |
+------+-------------+-------+------+---------------+------+---------+------+------+----------------+
1
row in set (0.00 sec)
MariaDB
[besttest]> explain select id,age from t1 order by age;
+------+-------------+-------+------+---------------+------+---------+------+------+----------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+----------------+
|
1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 1 | Using filesort |
+------+-------------+-------+------+---------------+------+---------+------+------+----------------+
1
row in set (0.00 sec)
|
e. Using join buffer
改值強調了在獲取連接條件時沒有使用索引,並且需要連接緩沖區來存儲中間結果。如果出現了這個值,那應該注意,根據查詢的具體情況可能需要添加索引來改進能。
1
2
3
4
5
6
7
8
|
MariaDB
[besttest]> explain select t1.name from t1 inner join t2 on t1.name=t2.name;
+------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+
|
1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 1 | |
|
1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL | 1 | Using where; Using join buffer (flat, BNL join) |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------------------------------------------+
2
rows in set (0.00 sec)
|
f. Impossible where
這個值強調了where語句會導致沒有符合條件的行。
1
2
3
4
5
6
7
|
MariaDB
[besttest]> EXPLAIN SELECT * FROM t1 WHERE 1=2;
+------+-------------+-------+------+---------------+------+---------+------+------+------------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+------------------+
|
1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Impossible WHERE |
+------+-------------+-------+------+---------------+------+---------+------+------+------------------+
1
row in set (0.00 sec)
|
h. Select tables optimized away
這個值意味着僅通過使用索引,優化器可能僅從聚合函數結果中返回一行.
1
2
3
4
5
6
7
|
MariaDB
[besttest]> explain select max(id) from t1;
+------+-------------+-------+------+---------------+------+---------+------+------+-------------------------+
|
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------------------+
|
1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No matching min/max row |
+------+-------------+-------+------+---------------+------+---------+------+------+-------------------------+
1
row in set (0.00 sec)
|
I. Index merges
當MySQL 決定要在一個給定的表上使用超過一個索引的時候,就會出現以下格式中的一個,詳細說明使用的索引以及合並的類型。
Using sort_union(…)
Using union(…)
Using intersect(…)
四、查詢性能優化
首先,讓我們來看一下SQL語句執行的過程,下面這個是我們平時寫的SQL語句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
SELECT DISTINCT
< select_list >
FROM
< left_table > < join_type >
JOIN < right_table > ON < join_condition >
WHERE
< where_condition >
GROUP BY
< group_by_list >
HAVING
< having_condition >
ORDER BY
< order_by_condition >
LIMIT < limit_number >
|
然而當數據庫接收到查詢請求以后會先對數據進行解析,解析后查詢順序就變成了下面這樣
1
2
3
4
5
6
7
8
9
10
|
FROM <left_table>
ON <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT
DISTINCT <select_list>
ORDER BY <order_by_condition>
LIMIT <limit_number>
|
了解了真實的MySQL查詢順序后,我們再來看一看SQL的優化目標。
- 減少IO次數
IO永遠是數據庫最容易瓶頸的地方,這是由數據庫的職責所決定的,大部分數據庫操作中超過90%的時間都是 IO 操作所占用的,減少 IO 次數是 SQL 優化中需要第一優先考慮,當然,也是收效最明顯的優化手段。
- 降低 CPU 計算
除了 IO 瓶頸之外,SQL優化中需要考慮的就是 CPU 運算量的優化了。order by, group by,distinct … 都是消耗 CPU 的大戶(這些操作基本上都是 CPU 處理內存中的數據比較運算)。當我們的 IO 優化做到一定階段之后,降低 CPU 計算也就成為了我們 SQL 優化的重要目標。
基於這個目標我們來看下優化的基本原則
- MySQL優化基本原則
1、選取最適用的字段類型,盡量避免浪費
MySQL可以很好的支持大數據量的存取,但是一般說來,數據庫中的表越小,在它上面執行的查詢也就會越快。因此,在創建表的時候,為了獲得更好的性能,我們可以將表中字段的寬度設得盡可能小。
例如,在定義郵政編碼這個字段時,如果將其設置為CHAR(255),顯然給數據庫增加了不必要的空間,甚至使用VARCHAR這種類型也是多余的,因為CHAR(6)就可以很好的完成任務了。同樣的,如果可以的話,我們應該使用MEDIUMINT而不是BIGIN來定義整型字段。盡量使用數字型字段,若只含數值信息的字段盡量不要設計為字符型,這會降低查詢和連接的性能,並會增加存儲開銷。這是因為引擎在處理查詢和連接時會逐個比較字符串中每一個字符,而對於數字型而言只需要比較一次就夠了。
另外一個提高效率的方法是在可能的情況下,應該盡量把字段設置為NOTNULL,這樣在將來執行查詢的時候,數據庫不用去比較NULL值。
2、使用連接(JOIN)來代替子查詢(Sub-Queries)
雖然Join 性能並不佳,但是和 MySQL 的子查詢比起來還是有非常大的性能優勢。MySQL 的子查詢執行計划一直存在較大的問題,雖然這個問題已經存在多年,但是到目前已經發布的所有穩定版本中都普遍存在,一直沒有太大改善。雖然官方也在很早就承認這一問題,並且承諾盡快解決,但是至少到目前為止我們還沒有看到哪一個版本較好的解決了這一問題。 在MySQL5.6或者更新的版本或者是MariaDB可以忽略關於子查詢方面的建議
3、使用聯合(UNION)來代替手動創建的臨時表
union查詢,它可以把需要使用臨時表的兩條或更多的select查詢合並的一個查詢中。在客戶端的查詢會話結束的時候,臨時表會被自動刪除,從而保證數據庫整齊、高效。使用union來創建查詢的時候,我們只需要用UNION作為關鍵字把多個select語句連接起來就可以了,要注意的是所有select語句中的字段數目要想同。
4、減少排序,為經常需要排序、分組和聯合查詢操作的字段建立索引
排序操作會消耗較多的 CPU 資源,所以減少排序可以在緩存命中率高等 IO 能力足夠的場景下會較大影響 SQL 的響應時間。 對於MySQL來說,減少排序有多種辦法,比如:
- 通過利用索引來排序的方式進行優化
- 減少參與排序的記錄條數
- 非必要不對數據進行排序
5、禁用外鍵
6、避免大sql
- 一個SQL只能在一個cpu上運行
- 高並發環境中,大SQL容易影響性能問題
- 可能一個大SQL把數據庫搞死 拆分SQL
7、保持事物的短小精悍
- 即開即用,用完即關
- 無關操作踢出事務,減少資源占用
- 保持一致性的前提下,拆分事務
8、避免大批量更新
- 避開高峰
- 白天限制速度
- 加sleep
9、避免取過量數據,靈活使用limit
當系統需要進行分頁操作的時候,盡量使用limit加上偏移量的方法來實現,同時配合order by的子句
10、避免在SQL 語句中進行數學運算、函數計算、邏輯判斷等操作
尤其需要注意,不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
11、避免OR
同一字段,推薦in 不同字段,推薦union
1
2
3
4
5
6
7
|
select id from t where num=10 or num=20
可以這樣查詢:
select id from t where num=10
union all
select id from t where num=20
|
當然是用in 或者 not in的時候也需要謹慎一些
1
|
select id from t where num in(1,2,3)
|
對於連續的數值,能用 between 就不要用 in 了:
1
|
select id from t where num between 1 and 3
|
12、優先優化高並發的 SQL,而不是執行頻率低某些“大”SQL
13、盡可能對每一條運行在數據庫中的SQL進行explain。
14、任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
五、mysql索引
MySQL索引的建立對於MySQL的高效運行是很重要的,索引可以大大提高MySQL的檢索速度。索引分單列索引和組合索引。單列索引,即一個索引只包含單個列,一個表可以有多個單列索引,但這不是組合索引。組合索引,即一個索引包含多個列。創建索引時,你需要確保該索引是應用在 SQL 查詢語句的條件(一般作為 WHERE 子句的條件)。
索引也會有它的缺點:雖然索引大大提高了查詢速度,同時卻會降低更新表的速度,如對表進行INSERT、UPDATE和DELETE。因為更新表時,MySQL不僅要保存數據,還要保存一下索引文件。
索引在設定的時候,會自動對數據進行排序,當一個表的數據超過800W+行以上的時候,索引的功能效果便不再明顯,建立索引會占用磁盤空間的索引文件,一般會選擇列值較短的,盡量使用列值唯一的。
索引的種類:
種類:B+樹索引
分類:主鍵、唯一、普通索引
1、普通索引
最普通的索引,所有列都可以加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
# 創建索引
CREATE INDEX indexName ON mytable(username(length));
# 修改表結構(添加索引)
ALTER table tableName ADD INDEX indexName(columnName)
# 創建表的時候直接指定
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
INDEX [indexName] (username(length))
);
# 查看索引
show index from mytable;
|
2、主鍵索引
建表的時候加的主鍵
1
2
3
4
5
6
|
CREATE TABLE besttest (
id int(10) AUTO_INCREMENT PRIMARY KEY NOT NULL,
mpp_name VARCHAR(20) NOT NULL UNIQUE,
mpp_age int(10) NOT NULL,
addree VARCHAR(50) NOT NULL
)
CHARSET utf8;
|
3、組合索引
1
|
create index index_name on table_name (col,col2);
|
4、唯一索引
它與前面的普通索引類似,不同的就是:索引列的值必須唯一,但允許有空值。如果是組合索引,則列值的組合必須唯一。它有以下幾種創建方式:
1
2
3
4
5
6
7
8
9
10
|
# 創建索引
CREATE UNIQUE INDEX indexName ON mytable(username(length))
# 修改表結構
ALTER table mytable ADD UNIQUE [indexName] (username(length))
# 創建表的時候直接指定
CREATE TABLE mytable(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
UNIQUE [indexName] (username(length))
);
|
那么我怎么樣知道我當前的表是否添加了索引呢?
1
|
SHOW INDEX FROM table_name; \G
|
六、優化MySQL服務設置
- 系統配置
系統配置一個指的是操作系統的配置,有一些操作系統的配置會影響mysql的性能,現在咱們大多數服務器都是用的linux服務器,linux上面一切東西都是基於文件的,mysql數據里面的表、數據等等都是文件存在磁盤上的。
linux系統有一個系統配置是文件打開的數量,默認是1024,也就是最多只能打開1024個文件,那在數據庫里面表比較多、並發大的情況下,這1024就不夠用了,要想獲取數據就得打開文件,但是打開文件的數量最多就1024個,就會導致有一些數據獲取不到,就得等待別的文件關閉之后,才能打開。那就要修改系統的配置,在/etc/security/limits.conf文件里面可以修改最大打開文件的數量。
1
2
3
|
vi /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536
|
還有一些mysql配置參數會影響mysql的性能。
sleep超時時間
mysql的連接數是提前配置好的,如果程序里面代碼寫的不好,有一些數據庫操作沒有及時關閉數據庫,那這個鏈接就不會釋放會一直占用鏈接,這樣子並發大的情況下,就會導致數據庫連接數不夠用了,就連接不上數據庫了。mysql默認8小時不操作數據庫才會自動關閉鏈接,所以這個sleep的超時時間會影響mysql的性能。
mysql5.6.6之前默認是共享的表空間,mysql5.6.6之后默認是開啟了獨立表空間的。
那什么是共享表空間呢?
就是說這個空間是所有的表都共享的,所有的表的數據都存在一個地方的。
你想一下,所有的貨架都存在一個倉庫里面的話,快遞員去拿貨的時候,人一多,可能進出都要排隊,拿貨的時候就比較慢了。
所以說共享表空間如果在數據量和並發量比較大的情況下,對IO的消耗是比較大的,影響性能。
共享表空間還有一個缺點就是不能自動收縮,自動收縮是什么意思呢,剛建表的時候,表里面數據很少,就1條數據,可能占用空間就幾kb,到后來數據多了,占用了10個G的空間,然后發現有一些數據都是垃圾數據,刪了5個G,那這個時候表空間就不會自動減小了,它還是10個G,浪費空間。
而獨立表空間就是每個表的表空間都是獨享的,用倉庫這個例子就是每個貨架都單獨在一個房間里頭,這樣的話快遞員去拿哪個東西,直接去那個房間里就好了,不用都擠在一個倉庫里了。
而使用了獨立的表空間,每個表都有自己的表空間,刪了數據也會自動收縮,就不會有上面的問題了。
1
2
|
set global innodb_file_per_table =ON; 設置獨立表空間打開
show variables like '%per_table%'; #查詢是否打開獨立表空間
|
讀/寫進程數配置
在mysql5.5之后讀、寫的進程數是可以配置的。默認讀和寫的進程數都是4個。
當然我們都知道,人多好干活嘛。進程多就是干活的人多,具體配置根據cpu的核數和業務邏輯來配置這兩個值。
假如cpu是32核的,那么就是同時可以有32個進程在運行,就可以把這兩個值給調大。
假如說是系統是一個內容類的網站,大多數操作都是讀操作,那么就可以把讀的進程數設置大一點,寫的進程數設置的小一點。
怎么修改呢,找到mysql的配置文件,在[mysqld]節點下加入下面參數的即可
1
2
|
innodb_read_io_threads =5 讀進程數
innodb_write_io_threads =3 寫進程數
|
七、監控mysql
Spotlight on mysql客戶端工具,有漂亮的ui界面,可以監控到mysql的io、qcache、連接數、buffer pool等等,還有預警的功能
Lepus,一個開源的國產監控平台,可以監控到mysql的慢查詢、 qcache、連接數、buffer pool等等,可以同時監控多台,配置多個實例即可
Zabbix,也是一個開源的監控平台,和lepus類似,配置比較復雜