最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL全局優(yōu)化與Mysql 8.0新特性示例詳解

 更新時(shí)間:2026年07月04日 16:15:57   作者:fengxin_rou  
MySQL 8引入多項(xiàng)新特性提升數(shù)據(jù)庫(kù)性能與管理靈活性,下面這篇文章主要介紹了MySQL全局優(yōu)化與Mysql 8.0新特性的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

知識(shí)體系總覽

MySQL全局優(yōu)化與Mysql 8.0新特性
├── 一、MySQL全局優(yōu)化總覽
│   └── ?1. 優(yōu)化優(yōu)先級(jí)(SQL索引 > 參數(shù)調(diào)優(yōu) > 硬件升級(jí))
├── 二、MySQL Server系統(tǒng)參數(shù)
│   ├── ?1. 連接相關(guān)(max_connections / max_user_connections / back_log)
│   ├── ?2. 超時(shí)相關(guān)(wait_timeout / interactive_timeout)
│   └── ?3. 查詢緩沖(sort_buffer_size / join_buffer_size)
├── 三、InnoDB引擎參數(shù)
│   ├── ?1. 核心參數(shù)(innodb_thread_concurrency / innodb_buffer_pool_size)
│   ├── ?2. 緩沖池命中率診斷
│   └── ?3. 鎖與日志相關(guān)(innodb_lock_wait_timeout / flush_log / sync_binlog)
├── 四、MySQL 8.0新特性詳解(16大特性)
│   ├── ?1. 降序索引 → ?2. group by不再隱式排序 → ?3. 隱藏索引
│   ├── ?4. 函數(shù)索引 → ?5. SKIP LOCKED / NOWAIT → ?6. innodb_dedicated_server
│   ├── ?7. 死鎖檢測(cè)開(kāi)關(guān) → ?8. undo獨(dú)立表空間 → ?9. binlog過(guò)期精確到秒
│   ├── ?10. 窗口函數(shù) → ?11. 默認(rèn)utf8mb4 → ?12. InnoDB系統(tǒng)表
│   ├── ?13. 元數(shù)據(jù)統(tǒng)一存儲(chǔ) → ?14. 自增主鍵持久化 → ?15. DDL原子化
│   └── ?16. 參數(shù)修改持久化(SET PERSIST)

一、MySQL全局優(yōu)化總覽

從上圖可以看出SQL及索引的優(yōu)化效果是最好的,而且成本最低,所以工作中我們要在這塊花更多時(shí)間。

補(bǔ)充一點(diǎn)配置文件my.ini或my.cnf的全局參數(shù):

假設(shè)服務(wù)器配置為:

  • CPU:32核
  • 內(nèi)存:64G
  • DISK:2T SSD

下面參數(shù)都是服務(wù)端參數(shù),默認(rèn)在配置文件的 [mysqld] 標(biāo)簽下。

二、MySQL Server系統(tǒng)參數(shù)

參考文檔:https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_max_connections

1. max_connections

最大連接數(shù)。 連接的創(chuàng)建和銷毀都需要系統(tǒng)資源,比如內(nèi)存、文件句柄,業(yè)務(wù)說(shuō)的支持多少并發(fā),指的是每秒請(qǐng)求數(shù),也就是QPS。

max_connections=3000

一個(gè)連接最少占用內(nèi)存是256K,最大是64M,如果一個(gè)連接的請(qǐng)求數(shù)據(jù)超過(guò)64MB(比如排序),就會(huì)申請(qǐng)臨時(shí)空間,放到硬盤(pán)上。

如果3000個(gè)用戶同時(shí)連上mysql,最小需要內(nèi)存3000256KB=750M,最大需要內(nèi)存300064MB=192G。

如果innodb_buffer_pool_size是40GB,給操作系統(tǒng)分配4G,給連接使用的最大內(nèi)存不到20G,如果連接過(guò)多,使用的內(nèi)存超過(guò)20G,將會(huì)產(chǎn)生磁盤(pán)SWAP,此時(shí)將會(huì)影響性能。連接數(shù)過(guò)高,不一定帶來(lái)吞吐量的提高,而且可能占用更多的系統(tǒng)資源。

2. max_user_connections

允許用戶連接的最大數(shù)量,剩余連接數(shù)用作DBA管理。

max_user_connections=2980

3. back_log

MySQL能夠暫存的連接數(shù)量。如果MySQL的連接數(shù)達(dá)到max_connections時(shí),新的請(qǐng)求將會(huì)被存在堆棧中,等待某一連接釋放資源,該堆棧數(shù)量即back_log,如果等待連接的數(shù)量超過(guò)back_log,將被拒絕。

back_log=300

4. wait_timeout

指的是app應(yīng)用通過(guò)jdbc連接mysql進(jìn)行操作完畢后,空閑300秒后斷開(kāi),默認(rèn)是28800,單位秒,即8個(gè)小時(shí)。

wait_timeout=300

5. interactive_timeout

指的是mysql client連接mysql進(jìn)行操作完畢后,空閑300秒后斷開(kāi),默認(rèn)是28800,單位秒,即8個(gè)小時(shí)。

interactive_timeout=300

6. sort_buffer_size

每個(gè)需要排序的線程分配該大小的一個(gè)緩沖區(qū)。增加該值可以加速ORDER BY 或 GROUP BY操作。

sort_buffer_size=4M

sort_buffer_size是一個(gè)connection級(jí)的參數(shù),在每個(gè)connection(session)第一次需要使用這個(gè)buffer的時(shí)候,一次性分配設(shè)置的內(nèi)存。

注意: sort_buffer_size并不是越大越好,由于是connection級(jí)的參數(shù),過(guò)大的設(shè)置+高并發(fā)可能會(huì)耗盡系統(tǒng)的內(nèi)存資源。例如:500個(gè)連接將會(huì)消耗500*sort_buffer_size(4M)=2G。

7. join_buffer_size

用于表關(guān)聯(lián)緩存的大小,和sort_buffer_size一樣,該參數(shù)對(duì)應(yīng)的分配內(nèi)存也是每個(gè)連接獨(dú)享。

join_buffer_size=4M

三、InnoDB引擎參數(shù)

參考文檔:https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_buffer_pool_size

1. innodb_thread_concurrency

此參數(shù)用來(lái)設(shè)置innodb線程的并發(fā)數(shù),默認(rèn)值為0表示不被限制,若要設(shè)置則與服務(wù)器的CPU核心數(shù)相同或是CPU的核心數(shù)的2倍,如果超過(guò)配置并發(fā)數(shù),則需要排隊(duì),這個(gè)值不宜太大,不然可能會(huì)導(dǎo)致線程之間鎖爭(zhēng)用嚴(yán)重,影響性能。

innodb_thread_concurrency=64

2. innodb_buffer_pool_size

innodb存儲(chǔ)引擎buffer pool緩存大小,一般為物理內(nèi)存的60%-70%。

內(nèi)存大小直接反應(yīng)數(shù)據(jù)庫(kù)的性能。

 innodb_buffer_pool_size=40G

如何判斷當(dāng)前數(shù)據(jù)庫(kù)的內(nèi)存是否已經(jīng)達(dá)到瓶頸了呢?

可以通過(guò)查看當(dāng)前服務(wù)器的狀態(tài),比較物理磁盤(pán)的讀取和內(nèi)存讀取的比例來(lái)判斷緩沖池的命中率,通常InnoDB存儲(chǔ)引擎的緩沖池的命中率不應(yīng)該小于99%,如:

show global status like 'innodb%read%'\G;

當(dāng)前服務(wù)器的狀態(tài)參數(shù):

  1. Innodb_buffer_pool_reads: 表示從物理磁盤(pán)讀取頁(yè)的次數(shù)
  2. Innodb_buffer_pool_read_ahead: 預(yù)讀的次數(shù)
  3. Innodb_buffer_pool_read_ahead_evicted: 預(yù)讀的頁(yè),但是沒(méi)有被讀取就從緩沖池中被替換的頁(yè)的數(shù)量,一般用來(lái)判斷預(yù)讀的效率
  4. Innodb_buffer_pool_read_requests: 從緩沖池中讀取頁(yè)的次數(shù)
  5. Innodb_data_reads: 總共讀入的字節(jié)數(shù)
  6. Innodb_data_reads: 發(fā)起讀取請(qǐng)求的次數(shù),每次讀取可能需要讀取多個(gè)頁(yè)

以下公式可以計(jì)算各種對(duì)緩沖池的操作:

緩沖池命中率計(jì)算公式:

命中率 = (Innodb_buffer_pool_read_requests - Innodb_buffer_pool_reads) / Innodb_buffer_pool_read_requests * 100%

?? 面試要點(diǎn): 緩沖池命中率是判斷內(nèi)存瓶頸的核心指標(biāo),通常應(yīng) ≥ 99%。若低于99%說(shuō)明物理磁盤(pán)讀取過(guò)多,需要擴(kuò)大buffer_pool或排查SQL問(wèn)題。

3. innodb_lock_wait_timeout

行鎖鎖定時(shí)間,默認(rèn)50s,根據(jù)公司業(yè)務(wù)定,沒(méi)有標(biāo)準(zhǔn)值。

 innodb_lock_wait_timeout=10

4. innodb_flush_log_at_trx_commit

參看上一節(jié)課內(nèi)容(redo log寫(xiě)入策略)。

 innodb_flush_log_at_trx_commit=1

5. sync_binlog

參看上一節(jié)課內(nèi)容(binlog寫(xiě)入策略)。

sync_binlog=1

參考文檔:https://dev.mysql.com/doc/refman/8.0/en/replication-options-binary-log.html

四、MySQL 8.0新特性詳解

建議使用8.0.17及之后的版本,更新的內(nèi)容比較多。

參考文檔:

  • 添加棄用和刪除的特性:https://dev.mysql.com/doc/refman/8.0/en/mysql-nutshell.html
  • 添加棄用和刪除的參數(shù):https://dev.mysql.com/doc/refman/8.0/en/added-deprecated-removed.html
  • MySQL8 InnoDB架構(gòu):https://dev.mysql.com/doc/refman/8.0/en/innodb-architecture.html

1. 新增降序索引

MySQL在語(yǔ)法上很早就已經(jīng)支持降序索引,但實(shí)際上創(chuàng)建的仍然是升序索引,如下MySQL 5.7 所示,c2字段降序,但是從show create table看c2仍然是升序。8.0可以看到,c2字段降序。只有Innodb存儲(chǔ)引擎支持降序索引。

# ====MySQL 5.7演示====
mysql> create table t1(c1 int,c2 int,index idx_c1_c2(c1,c2 desc));
Query OK, 0 rows affected (0.04 sec)

mysql> insert into t1 (c1,c2) values(1, 10),(2,50),(3,50),(4,100),(5,80);
Query OK, 5 rows affected (0.02 sec)

mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `c1` int(11) DEFAULT NULL,
  `c2` int(11) DEFAULT NULL,
  KEY `idx_c1_c2` (`c1`,`c2`)    --注意這里,c2字段是升序
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

mysql> explain select * from t1 order by c1,c2 desc;  --5.7也會(huì)使用索引,但是Extra字段里有filesort文件排序
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type  | possible_keys | key       | key_len | ref  | rows | filtered | Extra                       |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-----------------------------+
|  1 | SIMPLE      | t1    | NULL       | index | NULL          | idx_c1_c2 | 10      | NULL |    1 |   100.00 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.01 sec)
# ====MySQL 8.0演示====
mysql> create table t1(c1 int,c2 int,index idx_c1_c2(c1,c2 desc));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t1 (c1,c2) values(1, 10),(2,50),(3,50),(4,100),(5,80);
Query OK, 5 rows affected (0.02 sec)

mysql> show create table t1\G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `c1` int DEFAULT NULL,
  `c2` int DEFAULT NULL,
  KEY `idx_c1_c2` (`c1`,`c2` DESC)  --注意這里的區(qū)別,降序索引生效了
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

mysql> explain select * from t1 order by c1,c2 desc;  --Extra字段里沒(méi)有filesort文件排序,充分利用了降序索引
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key       | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | index | NULL          | idx_c1_c2 | 10      | NULL |    1 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from t1 order by c1 desc,c2;  --Extra字段里有Backward index scan,意思是反向掃描索引;
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key       | key_len | ref  | rows | filtered | Extra                            |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+----------------------------------+
|  1 | SIMPLE      | t1    | NULL       | index | NULL          | idx_c1_c2 | 10      | NULL |    1 |   100.00 | Backward index scan; Using index |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from t1 order by c1 desc,c2 desc;  --Extra字段里有filesort文件排序,排序必須按照每個(gè)字段定義的排序或按相反順序才能充分利用索引
mysql> explain select * from t1 order by c1,c2;    --Extra字段里有filesort文件排序

?? 關(guān)鍵理解: 降序索引使得ORDER BY中的ASC/DESC混合排序也能充分利用索引,避免filesort。注意排序字段必須按索引定義的順序或完全相反的順序,才能充分利用索引。

2. group by 不再隱式排序

mysql 8.0 對(duì)于group by 字段不再隱式排序,如需要排序,必須顯式加上order by 子句。

# ====MySQL 5.7演示====(group by默認(rèn)排序)
mysql> select count(*),c2 from t1 group by c2;
+----------+------+
| count(*) | c2   |
+----------+------+
|        1 |   10 |
|        2 |   50 |
|        1 |   80 |
|        1 |  100 |
+----------+------+
4 rows in set (0.00 sec)

# ====MySQL 8.0演示====(group by不再默認(rèn)排序)
mysql> select count(*),c2 from t1 group by c2;   --8.0版本group by不再默認(rèn)排序
+----------+------+
| count(*) | c2   |
+----------+------+
|        1 |   10 |
|        2 |   50 |
|        1 |  100 |
|        1 |   80 |
+----------+------+
4 rows in set (0.00 sec)

mysql> select count(*),c2 from t1 group by c2 order by c2;  --需要自己加order by
+----------+------+
| count(*) | c2   |
+----------+------+
|        1 |   10 |
|        2 |   50 |
|        1 |   80 |
|        1 |  100 |
+----------+------+
4 rows in set (0.00 sec)

3. 增加隱藏索引

使用 invisible 關(guān)鍵字在創(chuàng)建表或者進(jìn)行表變更中設(shè)置索引為隱藏索引。索引隱藏只是不可見(jiàn),但是數(shù)據(jù)庫(kù)后臺(tái)還是會(huì)維護(hù)隱藏索引的,在查詢時(shí)優(yōu)化器不使用該索引,即使用force index,優(yōu)化器也不會(huì)使用該索引,同時(shí)優(yōu)化器也不會(huì)報(bào)索引不存在的錯(cuò)誤,因?yàn)樗饕匀徽鎸?shí)存在,必要時(shí),也可以把隱藏索引快速恢復(fù)成可見(jiàn)。注意,主鍵不能設(shè)置為 invisible。

軟刪除就可以使用隱藏索引,比如我們覺(jué)得某個(gè)索引沒(méi)用了,刪除后發(fā)現(xiàn)這個(gè)索引在某些時(shí)候還是有用的,于是又得把這個(gè)索引加回來(lái),如果表數(shù)據(jù)量很大的話,這種操作耗費(fèi)時(shí)間是很多的,成本很高,這時(shí),我們可以將索引先設(shè)置為隱藏索引,等到真的確認(rèn)索引沒(méi)用了再刪除。

# 創(chuàng)建t2表,里面的c2字段為隱藏索引
mysql> create table t2(c1 int, c2 int, index idx_c1(c1), index idx_c2(c2) invisible);
Query OK, 0 rows affected (0.02 sec)

mysql> show index from t2\G
*************************** 1. row ***************************
        Table: t2
   Non_unique: 1
     Key_name: idx_c1
 Seq_in_index: 1
  Column_name: c1
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
      Visible: YES
   Expression: NULL
*************************** 2. row ***************************
        Table: t2
   Non_unique: 1
     Key_name: idx_c2
 Seq_in_index: 1
  Column_name: c2
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
      Visible: NO   --隱藏索引不可見(jiàn)
   Expression: NULL
2 rows in set (0.00 sec)

mysql> explain select * from t2 where c1=1;
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t2    | NULL       | ref  | idx_c1        | idx_c1 | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from t2 where c2=1;  --隱藏索引c2不會(huì)被使用
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t2    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> select @@optimizer_switch\G   --查看各種參數(shù)
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on,hash_join=on
1 row in set (0.00 sec)

mysql> set session optimizer_switch="use_invisible_indexes=on";  ----在會(huì)話級(jí)別設(shè)置查詢優(yōu)化器可以看到隱藏索引
Query OK, 0 rows affected (0.00 sec)

mysql> select @@optimizer_switch\G
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=on,skip_scan=on,hash_join=on
1 row in set (0.00 sec)

mysql> explain select * from t2 where c2=1;
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t2    | NULL       | ref  | idx_c2        | idx_c2 | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> alter table t2 alter index idx_c2 visible;
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> alter table t2 alter index idx_c2 invisible;
Query OK, 0 rows affected (0.01 sec)
Records: 0  Duplicates: 0  Warnings: 0

4. 新增函數(shù)索引

之前我們知道,如果在查詢中加入了函數(shù),索引不生效,所以MySQL 8引入了函數(shù)索引,MySQL 8.0.13開(kāi)始支持在索引中使用函數(shù)(表達(dá)式)的值。

函數(shù)索引基于虛擬列功能實(shí)現(xiàn),在MySQL中相當(dāng)于新增了一個(gè)列,這個(gè)列會(huì)根據(jù)你的函數(shù)來(lái)進(jìn)行計(jì)算結(jié)果,然后使用函數(shù)索引的時(shí)候就會(huì)用這個(gè)計(jì)算后的列作為索引。

mysql> create table t3(c1 varchar(10),c2 varchar(10));
Query OK, 0 rows affected (0.02 sec)

mysql> create index idx_c1 on t3(c1);     --創(chuàng)建普通索引
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create index func_idx on t3((UPPER(c2)));  --創(chuàng)建一個(gè)大寫(xiě)的函數(shù)索引
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from t3\G
*************************** 1. row ***************************
        Table: t3
   Non_unique: 1
     Key_name: idx_c1
 Seq_in_index: 1
  Column_name: c1
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
      Visible: YES
   Expression: NULL
*************************** 2. row ***************************
        Table: t3
   Non_unique: 1
     Key_name: func_idx
 Seq_in_index: 1
  Column_name: NULL
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment: 
Index_comment: 
      Visible: YES
   Expression: upper(`c2`)    --函數(shù)表達(dá)式
2 rows in set (0.00 sec)

mysql> explain select * from t3 where upper(c1)='ZHUGE';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t3    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from t3 where upper(c2)='ZHUGE';  --使用了函數(shù)索引
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key      | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t3    | NULL       | ref  | func_idx      | func_idx | 43      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

5. InnoDB存儲(chǔ)引擎select for update跳過(guò)鎖等待

對(duì)于 select … for share(8.0新增加查詢共享鎖的語(yǔ)法)或 select … for update, 在語(yǔ)句后面添加NOWAIT、SKIP LOCKED語(yǔ)法可以跳過(guò)鎖等待,或者跳過(guò)鎖定。

  • 在5.7及之前的版本,select…for update,如果獲取不到鎖,會(huì)一直等待,直到innodb_lock_wait_timeout超時(shí)。
  • 在8.0版本,通過(guò)添加nowait,skip locked語(yǔ)法,能夠立即返回。如果查詢的行已經(jīng)加鎖,那么nowait會(huì)立即報(bào)錯(cuò)返回,而skip locked也會(huì)立即返回,只是返回的結(jié)果中不包含被鎖定的行。

應(yīng)用場(chǎng)景: 比如查詢余票記錄,如果某些記錄已經(jīng)被鎖定,用skip locked可以跳過(guò)被鎖定的記錄,只返回沒(méi)有鎖定的記錄,提高系統(tǒng)性能。

# 先打開(kāi)一個(gè)session1:
mysql> select * from t1;
+------+------+
| c1   | c2   |
+------+------+
|    1 |   10 |
|    2 |   50 |
|    3 |   50 |
|    4 |  100 |
|    5 |   80 |
+------+------+
5 rows in set (0.00 sec)
    
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set c2 = 60 where c1 = 2;     --鎖定第二條記錄
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0


# 另外一個(gè)session2:    
mysql> select * from t1 where c1 = 2 for update;   --等待超時(shí)
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

mysql> select * from t1 where c1 = 2 for update nowait;   --查詢立即返回
ERROR 3572 (HY000): Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set.

mysql> select * from t1 for update skip locked;  --查詢立即返回,過(guò)濾掉了第二行記錄
+------+------+
| c1   | c2   |
+------+------+
|    1 |   10 |
|    3 |   50 |
|    4 |  100 |
|    5 |   80 |
+------+------+
4 rows in set (0.00 sec)

6. 新增innodb_dedicated_server自適應(yīng)參數(shù)

能夠讓InnoDB根據(jù)服務(wù)器上檢測(cè)到的內(nèi)存大小自動(dòng)配置innodb_buffer_pool_size,innodb_log_file_size等參數(shù),會(huì)盡可能多的占用系統(tǒng)可占用資源提升性能。解決非專業(yè)人員安裝數(shù)據(jù)庫(kù)后默認(rèn)初始化數(shù)據(jù)庫(kù)參數(shù)默認(rèn)值偏低的問(wèn)題,前提是服務(wù)器是專用來(lái)給MySQL數(shù)據(jù)庫(kù)的,如果還有其他軟件或者資源或者多實(shí)例MySQL使用,不建議開(kāi)啟該參數(shù),不然會(huì)影響其它程序。

mysql> show variables like '%innodb_dedicated_server%';   --默認(rèn)是OFF關(guān)閉,修改為ON打開(kāi)
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| innodb_dedicated_server | OFF   |
+-------------------------+-------+
1 row in set (0.02 sec)

7. 死鎖檢查控制

MySQL 8.0 (MySQL 5.7.15)增加了一個(gè)新的動(dòng)態(tài)變量 innodb_deadlock_detect,用于控制系統(tǒng)是否執(zhí)行 InnoDB 死鎖檢查,默認(rèn)是打開(kāi)的。死鎖檢測(cè)會(huì)耗費(fèi)數(shù)據(jù)庫(kù)性能的,對(duì)于高并發(fā)的系統(tǒng),我們可以關(guān)閉死鎖檢測(cè)功能,提高系統(tǒng)性能。但是我們要確保系統(tǒng)極少情況會(huì)發(fā)生死鎖,同時(shí)要將鎖等待超時(shí)參數(shù)調(diào)小一點(diǎn),以防出現(xiàn)死鎖等待過(guò)久的情況。

mysql> show variables like '%innodb_deadlock_detect%';  --默認(rèn)是打開(kāi)的
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_deadlock_detect | ON    |
+------------------------+-------+
1 row in set, 1 warning (0.01 sec)

8. undo文件不再使用系統(tǒng)表空間

默認(rèn)創(chuàng)建2個(gè)UNDO表空間,不再使用系統(tǒng)表空間。

9. binlog日志過(guò)期時(shí)間精確到秒

之前是天,并且參數(shù)名稱發(fā)生變化。在8.0版本之前,binlog日志過(guò)期時(shí)間設(shè)置都是設(shè)置expire_logs_days參數(shù),而在8.0版本中,MySQL默認(rèn)使用binlog_expire_logs_seconds參數(shù)。

10. 窗口函數(shù)(Window Functions):也稱分析函數(shù)

從 MySQL 8.0 開(kāi)始,新增了一個(gè)叫窗口函數(shù)的概念,它可以用來(lái)實(shí)現(xiàn)若干新的查詢方式。窗口函數(shù)與 SUM()、COUNT() 這種分組聚合函數(shù)類似,在聚合函數(shù)后面加上over()就變成窗口函數(shù)了,在括號(hào)里可以加上partition by等分組關(guān)鍵字指定如何分組,窗口函數(shù)即便分組也不會(huì)將多行查詢結(jié)果合并為一行,而是將結(jié)果放回多行當(dāng)中,即窗口函數(shù)不需要再使用 GROUP BY。

# 創(chuàng)建一張賬戶余額表
CREATE TABLE `account_channel` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '姓名',
  `channel` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '賬戶渠道',
  `balance` int DEFAULT NULL COMMENT '余額',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

# 插入一些示例數(shù)據(jù)
INSERT INTO `account_channel` (`id`, `name`, `channel`, `balance`) VALUES ('1', 'zhuge', 'wx', '100');
INSERT INTO `account_channel` (`id`, `name`, `channel`, `balance`) VALUES ('2', 'zhuge', 'alipay', '200');
INSERT INTO `account_channel` (`id`, `name`, `channel`, `balance`) VALUES ('3', 'zhuge', 'yinhang', '300');
INSERT INTO `account_channel` (`id`, `name`, `channel`, `balance`) VALUES ('4', 'lilei', 'wx', '200');
INSERT INTO `account_channel` (`id`, `name`, `channel`, `balance`) VALUES ('5', 'lilei', 'alipay', '100');
INSERT INTO `account_channel` (`id`, `name`, `channel`, `balance`) VALUES ('6', 'hanmeimei', 'wx', '500');

mysql> select * from account_channel;
+----+-----------+---------+---------+
| id | name      | channel | balance |
+----+-----------+---------+---------+
|  1 | zhuge     | wx      |     100 |
|  2 | zhuge     | alipay  |     200 |
|  3 | zhuge     | yinhang |     300 |
|  4 | lilei     | wx      |     200 |
|  5 | lilei     | alipay  |     100 |
|  6 | hanmeimei | wx      |     500 |
+----+-----------+---------+---------+
6 rows in set (0.00 sec)

mysql> select name,sum(balance) from account_channel group by name;
+-----------+--------------+
| name      | sum(balance) |
+-----------+--------------+
| zhuge     |          600 |
| lilei     |          300 |
| hanmeimei |          500 |
+-----------+--------------+
3 rows in set (0.00 sec)

# 在聚合函數(shù)后面加上over()就變成分析函數(shù)了,后面可以不用再加group by制定分組,因?yàn)樵趏ver里已經(jīng)用partition關(guān)鍵字指明了如何分組計(jì)算,這種可以保留原有表數(shù)據(jù)的結(jié)構(gòu),不會(huì)像分組聚合函數(shù)那樣每組只返回一條數(shù)據(jù)
mysql> select name,channel,balance,sum(balance) over(partition by name) as sum_balance from account_channel;
+-----------+---------+---------+-------------+
| name      | channel | balance | sum_balance |
+-----------+---------+---------+-------------+
| hanmeimei | wx      |     500 |         500 |
| lilei     | wx      |     200 |         300 |
| lilei     | alipay  |     100 |         300 |
| zhuge     | wx      |     100 |         600 |
| zhuge     | alipay  |     200 |         600 |
| zhuge     | yinhang |     300 |         600 |
+-----------+---------+---------+-------------+
6 rows in set (0.00 sec)

mysql> select name,channel,balance,sum(balance) over(partition by name order by balance) as sum_balance from account_channel;
+-----------+---------+---------+-------------+
| name      | channel | balance | sum_balance |
+-----------+---------+---------+-------------+
| hanmeimei | wx      |     500 |         500 |
| lilei     | alipay  |     100 |         100 |
| lilei     | wx      |     200 |         300 |
| zhuge     | wx      |     100 |         100 |
| zhuge     | alipay  |     200 |         300 |
| zhuge     | yinhang |     300 |         600 |
+-----------+---------+---------+-------------+
6 rows in set (0.00 sec)


# over()里如果不加條件,則默認(rèn)使用整個(gè)表的數(shù)據(jù)做運(yùn)算
mysql> select name,channel,balance,sum(balance) over() as sum_balance from account_channel;
+-----------+---------+---------+-------------+
| name      | channel | balance | sum_balance |
+-----------+---------+---------+-------------+
| zhuge     | wx      |     100 |        1400 |
| zhuge     | alipay  |     200 |        1400 |
| zhuge     | yinhang |     300 |        1400 |
| lilei     | wx      |     200 |        1400 |
| lilei     | alipay  |     100 |        1400 |
| hanmeimei | wx      |     500 |        1400 |
+-----------+---------+---------+-------------+
6 rows in set (0.00 sec)

mysql> select name,channel,balance,avg(balance) over(partition by name) as avg_balance from account_channel;
+-----------+---------+---------+-------------+
| name      | channel | balance | avg_balance |
+-----------+---------+---------+-------------+
| hanmeimei | wx      |     500 |    500.0000 |
| lilei     | wx      |     200 |    150.0000 |
| lilei     | alipay  |     100 |    150.0000 |
| zhuge     | wx      |     100 |    200.0000 |
| zhuge     | alipay  |     200 |    200.0000 |
| zhuge     | yinhang |     300 |    200.0000 |
+-----------+---------+---------+-------------+
6 rows in set (0.00 sec)

專用窗口函數(shù)分類:

  1. 序號(hào)函數(shù):ROW_NUMBER()、RANK()、DENSE_RANK()
  2. 分布函數(shù):PERCENT_RANK()、CUME_DIST()
  3. 前后函數(shù):LAG()、LEAD()
  4. 頭尾函數(shù):FIRST_VALUE()、LAST_VALUE()
  5. 其它函數(shù):NTH_VALUE()、NTILE()
# 按照balance字段排序,展示序號(hào)
mysql> select name,channel,balance,row_number() over(order by balance) as row_number1 from account_channel;
+-----------+---------+---------+-------------+
| name      | channel | balance | row_number1 |
+-----------+---------+---------+-------------+
| zhuge     | wx      |     100 |           1 |
| lilei     | alipay  |     100 |           2 |
| zhuge     | alipay  |     200 |           3 |
| lilei     | wx      |     200 |           4 |
| zhuge     | yinhang |     300 |           5 |
| hanmeimei | wx      |     500 |           6 |
+-----------+---------+---------+-------------+
6 rows in set (0.00 sec)

# 按照balance字段排序,first_value()選出排第一的余額
mysql> select name,channel,balance,first_value(balance) over(order by balance) as first1 from account_channel;
+-----------+---------+---------+--------+
| name      | channel | balance | first1 |
+-----------+---------+---------+--------+
| zhuge     | wx      |     100 |    100 |
| lilei     | alipay  |     100 |    100 |
| zhuge     | alipay  |     200 |    100 |
| lilei     | wx      |     200 |    100 |
| zhuge     | yinhang |     300 |    100 |
| hanmeimei | wx      |     500 |    100 |
+-----------+---------+---------+--------+
6 rows in set (0.01 sec)

11. 默認(rèn)字符集由latin1變?yōu)閡tf8mb4

在8.0版本之前,默認(rèn)字符集為latin1,utf8指向的是utf8mb3,8.0版本默認(rèn)字符集為utf8mb4,utf8默認(rèn)指向的也是utf8mb4。

12. MyISAM系統(tǒng)表全部換成InnoDB表

將系統(tǒng)表(mysql)和數(shù)據(jù)字典表全部改為InnoDB存儲(chǔ)引擎,默認(rèn)的MySQL實(shí)例將不包含MyISAM表,除非手動(dòng)創(chuàng)建MyISAM表。

13. 元數(shù)據(jù)存儲(chǔ)變動(dòng)

MySQL 8.0刪除了之前版本的元數(shù)據(jù)文件,例如表結(jié)構(gòu).frm等文件,全部集中放入mysql.ibd文件里??梢钥匆?jiàn)下圖test庫(kù)文件夾里已經(jīng)沒(méi)有了frm文件。

14. 自增變量持久化

在8.0之前的版本,自增主鍵AUTO_INCREMENT的值如果大于max(primary key)+1,在MySQL重啟后,會(huì)重置AUTO_INCREMENT=max(primary key)+1,這種現(xiàn)象在某些情況下會(huì)導(dǎo)致業(yè)務(wù)主鍵沖突或者其他難以發(fā)現(xiàn)的問(wèn)題。自增主鍵重啟重置的問(wèn)題很早就被發(fā)現(xiàn),一直到8.0才被解決,8.0版本將會(huì)對(duì)AUTO_INCREMENT值進(jìn)行持久化,MySQL重啟后,該值將不會(huì)改變。

# ====MySQL 5.7演示====
mysql> create table t(id int auto_increment primary key,c1 varchar(20));
Query OK, 0 rows affected (0.03 sec)

mysql> insert into t(c1) values('zhuge1'),('zhuge2'),('zhuge3');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  1 | zhuge1 |
|  2 | zhuge2 |
|  3 | zhuge3 |
+----+--------+
3 rows in set (0.00 sec)

mysql> delete from t where id = 3;
Query OK, 1 row affected (0.01 sec)

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  1 | zhuge1 |
|  2 | zhuge2 |
+----+--------+
2 rows in set (0.00 sec)

mysql> exit;
Bye

# 重啟MySQL服務(wù),并重新連接MySQL
mysql> insert into t(c1) values('zhuge4');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  1 | zhuge1 |
|  2 | zhuge2 |
|  3 | zhuge4 |
+----+--------+
3 rows in set (0.00 sec)

mysql> update t set id = 5 where c1 = 'zhuge1';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  2 | zhuge2 |
|  3 | zhuge4 |
|  5 | zhuge1 |
+----+--------+
3 rows in set (0.00 sec)

mysql> insert into t(c1) values('zhuge5');
Query OK, 1 row affected (0.01 sec)

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  2 | zhuge2 |
|  3 | zhuge4 |
|  4 | zhuge5 |
|  5 | zhuge1 |
+----+--------+
4 rows in set (0.00 sec)

mysql> insert into t(c1) values('zhuge6');
ERROR 1062 (23000): Duplicate entry '5' for key 'PRIMARY'



# ====MySQL 8.0演示====
mysql> create table t(id int auto_increment primary key,c1 varchar(20));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t(c1) values('zhuge1'),('zhuge2'),('zhuge3');
Query OK, 3 rows affected (0.00 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  1 | zhuge1 |
|  2 | zhuge2 |
|  3 | zhuge3 |
+----+--------+
3 rows in set (0.00 sec)

mysql> delete from t where id = 3;
Query OK, 1 row affected (0.01 sec)

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  1 | zhuge1 |
|  2 | zhuge2 |
+----+--------+
2 rows in set (0.00 sec)

mysql> exit;
Bye
[root@localhost ~]# service mysqld restart
Shutting down MySQL.... SUCCESS! 
Starting MySQL... SUCCESS! 

# 重新連接MySQL
mysql> insert into t(c1) values('zhuge4');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t;  --生成的id為4,不是3
+----+--------+
| id | c1     |
+----+--------+
|  1 | zhuge1 |
|  2 | zhuge2 |
|  4 | zhuge4 |
+----+--------+
3 rows in set (0.00 sec)

mysql> update t set id = 5 where c1 = 'zhuge1';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  2 | zhuge2 |
|  4 | zhuge4 |
|  5 | zhuge1 |
+----+--------+
3 rows in set (0.00 sec)

mysql> insert into t(c1) values('zhuge5');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t;
+----+--------+
| id | c1     |
+----+--------+
|  2 | zhuge2 |
|  4 | zhuge4 |
|  5 | zhuge1 |
|  6 | zhuge5 |
+----+--------+
4 rows in set (0.00 sec)

?? 面試要點(diǎn): MySQL 5.7中自增ID重啟后會(huì)被重置為max(id)+1,這可能導(dǎo)致主鍵沖突。8.0將AUTO_INCREMENT持久化到redo log,徹底解決此問(wèn)題。

15. DDL原子化

InnoDB表的DDL支持事務(wù)完整性,要么成功要么回滾。

MySQL 8.0 開(kāi)始支持原子 DDL 操作,其中與表相關(guān)的原子 DDL 只支持 InnoDB 存儲(chǔ)引擎。一個(gè)原子 DDL 操作內(nèi)容包括:更新數(shù)據(jù)字典,存儲(chǔ)引擎層的操作,在 binlog 中記錄 DDL 操作。

支持與表相關(guān)的 DDL:數(shù)據(jù)庫(kù)、表空間、表、索引的 CREATE、ALTER、DROP 以及 TRUNCATE TABLE。支持的其它 DDL :存儲(chǔ)程序、觸發(fā)器、視圖、UDF 的 CREATE、DROP 以及ALTER 語(yǔ)句。支持賬戶管理相關(guān)的 DDL:用戶和角色的 CREATE、ALTER、DROP 以及適用的 RENAME等等。

# MySQL 5.7
mysql> drop table t1,t2;  //刪除表報(bào)錯(cuò)不會(huì)回滾,t1表會(huì)被刪除
ERROR 1051 (42S02): Unknown table 'test.t2'
mysql> show tables;  -- t1表已經(jīng)不見(jiàn)了!

# MySQL 8.0
mysql> drop table t1,t2;  //刪除表報(bào)錯(cuò)會(huì)回滾,t1表依然還在
ERROR 1051 (42S02): Unknown table 'test.t2'
mysql> show tables;  -- t1表還在!

16. 參數(shù)修改持久化

MySQL 8.0版本支持在線修改全局參數(shù)并持久化,通過(guò)加上PERSIST關(guān)鍵字,可以將修改的參數(shù)持久化到新的配置文件(mysqld-auto.cnf)中,重啟MySQL時(shí),可以從該配置文件獲取到最新的配置參數(shù)。

set global 設(shè)置的變量參數(shù)在mysql重啟后會(huì)失效。

mysql> set persist innodb_lock_wait_timeout=25;

系統(tǒng)會(huì)在數(shù)據(jù)目錄下生成一個(gè)包含json格式的mysqld-auto.cnf 的文件:

{
    "Version": 1,
    "mysql_server": {
        "innodb_lock_wait_timeout": {
            "Value": "25",
            "Metadata": {
                "Timestamp": 1675290252103863,
                "User": "root",
                "Host": "localhost"
            }
        }
    }
}

?? 關(guān)鍵理解: SET PERSIST 將參數(shù)修改持久化到 mysqld-auto.cnf,重啟后仍然生效。該文件優(yōu)先級(jí)高于 my.cnf。

總結(jié) 

到此這篇關(guān)于MySQL全局優(yōu)化與Mysql 8.0新特性的文章就介紹到這了,更多相關(guān)MySQL全局優(yōu)化與8.0新特性內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

鄂尔多斯市| 郓城县| 平阴县| 靖江市| 镇巴县| 富阳市| 法库县| 阿瓦提县| 东乌珠穆沁旗| 舞阳县| 南投县| 丰宁| 房产| 建宁县| 广南县| 栾城县| 南陵县| 邓州市| 孟津县| 屯昌县| 淄博市| 兴业县| 衡南县| 连城县| 花莲市| 大兴区| 秦皇岛市| 博野县| 长治市| 喀喇沁旗| 南康市| 鸡西市| 离岛区| 阿克苏市| 仁寿县| 大新县| 陈巴尔虎旗| 五莲县| 永兴县| 伊川县| 乌鲁木齐市|