MySQL相關(終結篇二)- SQL 語句分析與優化

前言

關於前面講過的知識點我就再也不贅述了,還沒看過的朋友能夠進入個人首頁進行查閱(前言部分附贈飛機票)。這篇文章將是整個專題的總結,並且也是面試官會問到的最高頻率的一個問題——「你對 MySQL 的性能優化有什麼想法?」php

不少出去面試的朋友應該基本上都會被問到這個問題,可是可能可以回答得盡善盡美的比較少,看過我專題且可以消化成本身肚子裏的東西的朋友應該能夠吊打面試官了哈哈哈哈(針對中高級),但願今天這篇文章以後你們可以對本身腦海中零散知識點進行整合整理,我盼着大家能回來給我報喜(固然吐苦水也能夠),也盼着能跟你們一塊兒不斷進步。html

回到正題,關於此次的 MySQL 性能優化的知識點,我會分紅兩篇幅的文章來輸出,關於 SQL 語句的性能優化我會以單獨的篇幅來進行編寫,語句優化在實操中是屬於性能優化的最高級別的優化點,但願你們也能好好消化。mysql

這個 MySQL 專題是我從年前就一直在準備的,恰好過年在家也沒事就一直在思考着要怎麼去發表這部分的文章,讓你們可以看的時候思路比較清晰,記憶可以更加深入,最後我是經過先發布腦圖,而後再根據腦圖的方向進行專題知識點的發表,以後應該也會是這種形式,畢竟,這樣我寫文章思路清晰,你們看文章的時候思路也清晰嘛,複習知識點的時候也能夠根據腦圖來。程序員

博文是我從去年開始寫的,以前是本身在雲筆記上作筆記比較多。我以爲作筆記寫總結對自我提高有很大的幫助,而分享出來,也是但願你們可以從中學到新的知識,同時也能幫助我一塊兒不斷改進,給我提一些建議,讓我在給你們分享總結的東西的同時本身也能查缺補漏(再次感謝一直以來支持個人朋友們 Thanks♪(・ω・)ノ)面試

關於下一個專題我還沒想好要寫什麼,你們若是有什麼想法的話能夠在公衆號給我留言。spring

這個篇章是性能優化篇章兄弟篇,SQL語句優化,在面試中也是重中之重,但願各位小夥伴重視。sql

老規矩,先上飛機票:數據庫

  1. MySQL相關(一)- 一條查詢語句是如何執行的
  2. MySQL相關(二)- 一條更新語句是如何執行的
  3. MySQL相關(番外篇)- innodb 邏輯存儲結構
  4. MySQL相關(三)- 索引數據模型推演及 B+Tree 的詳細介紹
  5. MySQL相關(四)- 性能優化關鍵點索引
  6. MySQL相關(五)- 事務特性及隔離級別的詳細介紹
  7. MySQL相關(六)- 事務隔離級別的實現方案(MVCC)
  8. MySQL相關(七)- innodb 鎖的介紹及使用
  9. MySQL相關(八)- innodb行級鎖深刻剖析
  10. MySQL相關(九)- 死鎖的發生和避免

前面提到的腦圖以下,想要完整高清圖片能夠到微信個人公衆號下【6曦軒】下回復 MySQL 腦圖獲取: 性能優化

在這裏插入圖片描述

正文

優化器——SQL 語句分析與優化

優化器就是對咱們的 SQL 語句進行分析,生成執行計劃。bash

咱們作項目的時候,有時會收到 DBA 的郵件,裏面列出了咱們項目上幾個耗時比較長的查詢語句,讓咱們去優化,這些語句是從哪裏來的呢?

咱們的服務層天天執行了這麼多 SQL 語句,它怎麼知道哪些 SQL 語句比較慢呢?首先,咱們要把 SQL 執行狀況記錄下來。

慢查詢日誌 slow query log

官網說明:dev.mysql.com/doc/refman/…

打開慢日誌開關

由於開啓慢查詢日誌是有代價的(跟 binlog、optimizer-trace 同樣),因此在 MySQL 中,它默認是關閉的:

show variables like 'slow_query%';
複製代碼

在這裏插入圖片描述
除了這個開關,還有一個參數,控制執行超過多長時間的 SQL 才記錄到慢日誌,默認是 10 秒。

show variables like '%slow_query%';
複製代碼

能夠直接動態修改參數(重啓後失效)。

set @@global.slow_query_log=1;	-- 1 開啓,0 關閉,重啓後失效

set @@global.long_query_time=3;	-- mysql 默認的慢查詢時間是 10 秒,另開一個窗口後纔會查到最新值

show variables like '%long_query%';

show variables like '%slow_query%';
複製代碼

或者修改配置文件 my.cnf。

如下配置定義了慢查詢日誌的開關、慢查詢的時間、日誌文件的存放路徑。

slow_query_log = ON

long_query_time=2

slow_query_log_file =/var/lib/mysql/localhost-slow.log
複製代碼

模擬慢查詢:

select sleep(10);
複製代碼

查詢 user_innodb 表的 500 萬數據(檢查是否是沒有索引)。

SELECT * FROM `user_innodb` where phone = '136';
複製代碼

慢日誌分析

  1. 日誌內容
show global status like 'slow_queries'; -- 查看有多少慢查詢 show variables like '%slow_query%'; -- 獲取慢日誌目錄

cat /var/lib/mysql/ localhost-slow.log
複製代碼

在這裏插入圖片描述
有了慢查詢日誌,怎麼去分析統計呢?好比 SQL 語句的出現的慢查詢次數最多,平均每次執行了多久?

  1. mysqldumpslow

經過官網的說明來看一下:dev.mysql.com/doc/refman/…

MySQL 提供了 mysqldumpslow 的工具,在 MySQL 的 bin 目錄下。

mysqldumpslow --help
複製代碼

例如:查詢用時最多的 20 條慢 SQL:

mysqldumpslow -s t -t 20 -g 'select' /var/lib/mysql/localhost-slow.log
複製代碼

Count 表明這個 SQL 執行了多少次;

Time 表明執行的時間,括號裏面是累計時間;

Lock 表示鎖定的時間,括號是累計;

Rows 表示返回的記錄數,括號是累計。

除了慢查詢日誌以外,還有一個 SHOW PROFILE 工具可使用。

SHOW PROFILE

dev.mysql.com/doc/refman/…

SHOW PROFILE 是谷歌高級架構師 Jeremy Cole 貢獻給 MySQL 社區的,能夠查看SQL 語句執行的時候使用的資源,好比 CPU、IO 的消耗狀況。

在 SQL 中輸入 help profile 能夠獲得詳細的幫助信息。

查看是否開啓

select @@profiling;

set @@profiling=1;
複製代碼

查看 profile 統計

show profiles;//命令最後帶一個 s
複製代碼

在這裏插入圖片描述
查看最後一個 SQL 的執行詳細信息,從中找出耗時較多的環節(沒有 s)。

show profile;//沒有 s
複製代碼

在這裏插入圖片描述
6.2E-5,小數點左移 5 位,表明 0.000062 秒。

也能夠根據 ID 查看執行詳細信息,在後面帶上 for query + ID。

show profile for query 1;
複製代碼

除了慢日誌和 show profile,若是要分析出當前數據庫中執行的慢的 SQL,還能夠經過查看運行線程狀態和服務器運行信息、存儲引擎信息來分析。

其餘系統命令

show processlist 運行線程

https://dev.mysql.com/doc/refman/5.7/en/show-processlist.html

show processlist;
複製代碼

這是很重要的一個命令,用於顯示用戶運行線程。能夠根據 id 號 kill 線程。

也能夠查表,效果同樣:

select * from information_schema.processlist;
複製代碼

在這裏插入圖片描述

含義
Id 線程的惟一標誌,能夠根據它 kill 線程
User 啓動這個線程的用戶,普通用戶只能看到本身的線程
Host 哪一個 IP 端口發起的鏈接
db 操做的數據庫
Command 線程的命令 dev.mysql.com/doc/refman/…
Time 操做持續時間,單位秒
State 線程狀態,好比查詢可能有 copying to tmp table,Sorting result,Sending data dev.mysql.com/doc/refman/…
Info SQL 語句的前 100 個字符,若是要查看完整的 SQL 語句,用 SHOW FULL PROCESSLIST

show status 服務器運行狀態

dev.mysql.com/doc/refman/…

SHOW STATUS 用於查看 MySQL 服務器運行狀態(重啓後會清空),有 session

和 global 兩種做用域,格式:參數-值。

能夠用 like 帶通配符過濾。

SHOW GLOBAL STATUS LIKE 'com_select'; -- 查看 select 次數

show engine 存儲引擎運行信息

dev.mysql.com/doc/refman/…

show engine 用來顯示存儲引擎的當前運行信息,包括事務持有的表鎖、行鎖信息;

事務的鎖等待狀況;線程信號量等待;文件 IO 請求;buffer pool 統計信息。

例如:

show engine innodb status;
複製代碼

若是須要將監控信息輸出到錯誤信息 error log 中(15 秒鐘一次),能夠開啓輸出。

show variables like 'innodb_status_output%';

--開啓輸出:

SET GLOBAL innodb_status_output=ON;

SET GLOBAL innodb_status_output_locks=ON;
複製代碼

咱們如今已經知道了這麼多分析服務器狀態、存儲引擎狀態、線程運行信息的命令,若是讓你去寫一個數據庫監控系統,你會怎麼作?

其實不少開源的慢查詢日誌監控工具,他們的原理其實也都是讀取的系統的變量和狀態。

如今咱們已經知道哪些 SQL 慢了,爲何慢呢?慢在哪裏?

MySQL 提供了一個執行計劃的工具(在架構中咱們有講到,優化器最終生成的就是一個執行計劃),其餘數據庫,例如 Oracle 也有相似的功能。

經過 EXPLAIN 咱們能夠模擬優化器執行 SQL 查詢語句的過程,來知道 MySQL 是怎麼處理一條 SQL 語句的。經過這種方式咱們能夠分析語句或者表的性能瓶頸。

explain 能夠分析 update、delete、insert 麼?

MySQL 5.6.3 之前只能分析 SELECT; MySQL5.6.3 之後就能夠分析 update、delete、 insert 了。

EXPLAIN 執行計劃

官方連接:dev.mysql.com/doc/refman/…

咱們先建立三張表。一張課程表,一張老師表,一張老師聯繫方式表(沒有任何索引)。

DROP TABLE IF EXISTS course;

CREATE TABLE `course` (
	`cid` int(3) DEFAULT NULL,
	`cname` varchar(20) DEFAULT NULL,
	`tid` int(3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

DROP TABLE IF EXISTS teacher;

CREATE TABLE `teacher` (
	`tid` int(3) DEFAULT NULL,
	`tname` varchar(20) DEFAULT NULL,
	`tcid` int(3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

DROP TABLE IF EXISTS teacher_contact;

CREATE TABLE `teacher_contact` (
	`tcid` int(3) DEFAULT NULL,
	`phone` varchar(200) DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

​INSERT INTO `course` VALUES ('1', 'mysql', '1');

INSERT INTO `course` VALUES ('2', 'jvm', '1');

INSERT INTO `course` VALUES ('3', 'juc', '2');

INSERT INTO `course` VALUES ('4', 'spring', '3');

INSERT INTO `teacher` VALUES ('1', 'jerry', '1');

INSERT INTO `teacher` VALUES ('2', 'jack', '2');

INSERT INTO `teacher` VALUES ('3', 'mic', '3');

INSERT INTO `teacher_contact` VALUES ('1', '13688888888');

INSERT INTO `teacher_contact` VALUES ('2', '18166669999');

INSERT INTO `teacher_contact` VALUES ('3', '17722225555');
複製代碼

explain 的結果有不少的字段,咱們詳細地分析一下。

先確認一下環境:

select version();
show variables like '%engine%';
複製代碼

id

id 是查詢序列編號。

id 值不一樣

id 值不一樣的時候,先查詢 id 值大的(先大後小)。

--查詢 mysql 課程的老師手機號

EXPLAIN SELECT tc.phone FROM teacher_contact tc WHERE tcid = (
	SELECT tcid FROM teacher t WHERE t.tid = ( SELECT c.tid FROM course c WHERE c.cname = 'mysql')
);
複製代碼

查詢順序:course c——teacher t——teacher_contact tc。

在這裏插入圖片描述

先查課程表,再查老師表,最後查老師聯繫方式表。子查詢只能以這種方式進行,只有拿到內層的結果以後才能進行外層的查詢。

id 值相同

--查詢課程 ID 爲 2,或者聯繫表 ID 爲 3 的老師

EXPLAIN
SELECT t.tname,c.cname,tc.phone
FROM teacher t, course c, teacher_contact tc WHERE t.tid = c.tid
AND t.tcid = tc.tcid AND (c.cid = 2 OR tc.tcid = 3);
複製代碼

id 值相同時,表的查詢順序是從上往下順序執行。例如此次查詢的 id 都是 1,查詢的順序是 teacher t(3 條)——course c(4 條)——teacher_contact tc(3 條)。

teacher 表插入 3 條數據後:

INSERT INTO `teacher` VALUES (4, 'james', 4);

INSERT INTO `teacher` VALUES (5, 'tom', 5);

INSERT INTO `teacher` VALUES (6, 'seven', 6);

COMMIT;
複製代碼
--(備份)恢復語句

DELETE FROM teacher where tid in (4,5,6);

COMMIT;
複製代碼

id 也都是 1,可是從上往下查詢順序變成了:teacher_contact tc(3 條)——teacher t(6 條)——course c(4 條)。

在這裏插入圖片描述

爲何數據量不一樣的時候順序會發生變化呢?這個是由笛卡爾積決定的。

舉例:假若有 a、b、c 三張表,分別有 二、三、4 條數據,若是作三張表的聯合查詢,當查詢順序是 a→b→c 的時候,它的笛卡爾積是:234=64=24。若是查詢順序是 c →b→a,它的笛卡爾積是 432=122=24。

由於 MySQL 要把查詢的結果,包括中間結果和最終結果都保存到內存,因此 MySQL 會優先選擇中間結果數據量比較小的順序進行查詢。因此最終聯表查詢的順序是 a→b→ c。這個就是爲何 teacher 表插入數據之後查詢順序會發生變化。

(小表驅動大表的思想)

既有相同也有不一樣若是 ID 有相同也有不一樣,就是 ID 不一樣的先大後小,ID 相同的從上往下。

select type 查詢類型

這裏並無列舉所有(其它:DEPENDENT UNION、DEPENDENT SUBQUERY、MATERIALIZED、UNCACHEABLE SUBQUERY、UNCACHEABLE UNION)。

下面列舉了一些常見的查詢類型:

  • SIMPLE

簡單查詢,不包含子查詢,不包含關聯查詢 union。 EXPLAIN SELECT * FROM teacher;

在這裏插入圖片描述
再看一個包含子查詢的案例: --查詢 mysql 課程的老師手機號 EXPLAIN SELECT tc.phone FROM teacher_contact tc WHERE tcid = (SELECT tcid FROM teacher t WHERE t.tid = ( SELECT c.tid FROM course c WHERE c.cname = 'mysql'));
在這裏插入圖片描述

  • PRIMARY

子查詢 SQL 語句中的主查詢,也就是最外面的那層查詢。

  • SUBQUERY

子查詢中全部的內層查詢都是 SUBQUERY 類型的。

  • DERIVED

衍生查詢,表示在獲得最終查詢結果以前會用到臨時表。例如: --查詢 ID 爲 1 或 2 的老師教授的課程 EXPLAIN SELECT cr.cname FROM (SELECT * FROM course WHERE tid = 1UNIONSELECT * FROM course WHERE tid = 2 ) cr;

在這裏插入圖片描述
對於關聯查詢,先執行右邊的 table(UNION),再執行左邊的 table,類型是DERIVED。

  • UNION

用到了 UNION 查詢。同上例。

  • UNION RESULT

主要是顯示哪些表之間存在 UNION 查詢。<union2,3>表明 id=2 和 id=3 的查詢存在 UNION。同上例。

type 鏈接類型

dev.mysql.com/doc/refman/…

全部的鏈接類型中,上面的最好,越往下越差。

在經常使用的連接類型中:system > const > eq_ref > ref > range > index > all

這 裏 並 沒 有 列 舉 全 部 ( 其 他 : fulltext 、 ref_or_null 、 index_merger 、unique_subquery、index_subquery)。

以上訪問類型除了 all,都能用到索引。

  • const

主鍵索引或者惟一索引,只能查到一條數據的 SQL。

DROP TABLE IF EXISTS single_data;
CREATE TABLE single_data(
	id int(3) PRIMARY KEY,
	content varchar(20)
);
insert into single_data values(1,'a');
EXPLAIN SELECT * FROM single_data a where id = 1;
複製代碼

在這裏插入圖片描述

  • system

system 是 const 的一種特例,只有一行知足條件。例如:只有一條數據的系統表。 EXPLAIN SELECT * FROM mysql.proxies_priv;

在這裏插入圖片描述

  • eq_ref

一般出如今多表的 join 查詢,表示對於前表的每個結果,,都只能匹配到後表的一行結果。通常是惟一性索引的查詢(UNIQUE 或 PRIMARY KEY)。
eq_ref 是除 const 以外最好的訪問類型。
先刪除 teacher 表中多餘的數據,teacher_contact 有 3 條數據,teacher 表有 3 條數據。

DELETE FROM teacher where tid in (4,5,6);
commit;
複製代碼
--備份
INSERT INTO `teacher` VALUES (4, 'james', 4);
INSERT INTO `teacher` VALUES (5, 'tom', 5);
INSERT INTO `teacher` VALUES (6, 'seven', 6);
commit;
複製代碼

爲 teacher_contact 表的 tcid(第一個字段)建立主鍵索引。 --ALTER TABLE teacher_contact DROP PRIMARY KEY; ALTER TABLE teacher_contact ADD PRIMARY KEY(tcid); 爲teacher 表的 tcid(第三個字段)建立普通索引。 --ALTER TABLE teacher DROP INDEX idx_tcid; ALTER TABLE teacher ADD INDEX idx_tcid (tcid); 執行如下 SQL 語句: select t.tcid from teacher t,teacher_contact tc where t.tcid = tc.tcid;

在這裏插入圖片描述
此時的執行計劃(teacher_contact 表是 eq_ref):
在這裏插入圖片描述

小結:

以上三種 system,const,eq_ref,都是可遇而不可求的,基本上很難優化到這個狀態。

  • ref

查詢用到了非惟一性索引,或者關聯操做只使用了索引的最左前綴。 例如:使用 tcid 上的普通索引查詢: explain SELECT * FROM teacher where tcid = 3;

在這裏插入圖片描述

  • range

索引範圍掃描。 若是 where 後面是 between and 或 <或 > 或 >= 或 <=或 in 這些,type 類型就爲 range。 不走索引必定是全表掃描(ALL),因此先加上普通索引。 --ALTER TABLE teacher DROP INDEX idx_tid; ALTER TABLE teacher ADD INDEX idx_tid (tid); 執行範圍查詢(字段上有普通索引): EXPLAIN SELECT * FROM teacher t WHERE t.tid <3; --或 EXPLAIN SELECT * FROM teacher t WHERE tid BETWEEN 1 AND 2;

在這裏插入圖片描述
IN 查詢也是 range(字段有主鍵索引) EXPLAIN SELECT * FROM teacher_contact t WHERE tcid in (1,2,3);
在這裏插入圖片描述

  • index

Full Index Scan,查詢所有索引中的數據(比不走索引要快)。 EXPLAIN SELECT tid FROM teacher;

在這裏插入圖片描述

  • all

Full Table Scan,若是沒有索引或者沒有用到索引,type 就是 ALL。表明全表掃描。

  • NULL

不用訪問表或者索引就能獲得結果,例如: EXPLAIN select 1 from dual where 1=1;

小結:

通常來講,須要保證查詢至少達到 range 級別,最好能達到 ref。

ALL(全表掃描)和 index(查詢所有索引)都是須要優化的。

possible_key、key

可能用到的索引和實際用到的索引。若是是 NULL 就表明沒有用到索引。 possible_key 能夠有一個或者多個,可能用到索引不表明必定用到索引。反過來,possible_key 爲空,key 可能有值嗎?表上建立聯合索引:

ALTER TABLE user_innodb DROP INDEX comidx_name_phone;
ALTER TABLE user_innodb add INDEX comidx_name_phone (name,phone);
複製代碼

執行計劃(改爲 select name 也能用到索引):

explain select phone from user_innodb where phone='126';
複製代碼

在這裏插入圖片描述

結論:是有可能的(這裏是覆蓋索引的狀況)。

若是經過分析發現沒有用到索引,就要檢查 SQL 或者建立索引。

key_len

索引的長度(使用的字節數)。跟索引字段的類型、長度有關。

rows

MySQL 認爲掃描多少行才能返回請求的數據,是一個預估值。通常來講行數越少越好。

filtered

這個字段表示存儲引擎返回的數據在 server 層過濾後,剩下多少知足查詢的記錄數量的比例,它是一個百分比。

ref

使用哪一個列或者常數和索引一塊兒從表中篩選數據。

Extra

執行計劃給出的額外的信息說明。

using index

用到了覆蓋索引,不須要回表。

EXPLAIN SELECT tid FROM teacher ;
複製代碼

using where

使用了 where 過濾,表示存儲引擎返回的記錄並非全部的都知足查詢條件,須要在 server 層進行過濾(跟是否使用索引沒有關係)。

EXPLAIN select * from user_innodb where phone ='13866667777';
複製代碼

在這裏插入圖片描述

Using index condition(索引條件下推)

索引下推,在前面的文章中已經講解過了。

dev.mysql.com/doc/refman/…

using filesort

不能使用索引來排序,用到了額外的排序(跟磁盤或文件沒有關係)。須要優化。(複合索引的前提)

ALTER TABLE user_innodb DROP INDEX comidx_name_phone;
ALTER TABLE user_innodb add INDEX comidx_name_phone (name,phone);
複製代碼
EXPLAIN select * from user_innodb where name ='青山' order by id;
複製代碼

(order by id 引發)

在這裏插入圖片描述

using temporary

用到了臨時表。例如(如下不是所有的狀況):

一、distinct 非索引列

EXPLAIN select DISTINCT(tid) from teacher t;
複製代碼

二、group by 非索引列

EXPLAIN select tname from teacher group by tname;
複製代碼

三、使用 join 的時候,group 任意列

EXPLAIN select t.tid from teacher t join course c on t.tid = c.tid group by t.tid;
複製代碼

須要優化,例如建立複合索引。

總結一下:

模擬優化器執行 SQL 查詢語句的過程,來知道 MySQL 是怎麼處理一條 SQL 語句的。

經過這種方式咱們能夠分析語句或者表的性能瓶頸。

分析出問題以後,就是對 SQL 語句的具體優化。

好比怎麼用到索引,怎麼減小鎖的阻塞等待,在前面兩次課已經講過。

SQL 與索引優化

當咱們的 SQL 語句比較複雜,有多個關聯和子查詢的時候,就要分析 SQL 語句有沒有改寫的方法。

舉個簡單的例子,如出一轍的數據:

--大偏移量的 limit

select * from user_innodb limit 900000,10;
複製代碼

--改爲先過濾 ID,再 limit

SELECT * FROM user_innodb WHERE id >= 900000 LIMIT 10;
複製代碼

對於具體的 SQL 語句的優化,MySQL 官網也提供了不少建議,這個是咱們在分析具體的 SQL 語句的時候須要注意的,也是你們在之後的工做裏面要去慢慢地積累的(這裏咱們就不一一地分析了)。

dev.mysql.com/doc/refman/…

存儲引擎

存儲引擎的選擇

爲不一樣的業務表選擇不一樣的存儲引擎,例如:查詢插入操做多的業務表,用 MyISAM。

臨時數據用 Memeroy。常規的併發大更新多的表用 InnoDB。

分區或者分表

分區不推薦。

交易歷史表:在年末爲下一年度創建 12 個分區,每月一個分區。

渠道交易表:分紅當日表;當月表;歷史表,歷史表再作分區。

字段定義

原則:使用能夠正確存儲數據的最小數據類型。

爲每一列選擇合適的字段類型:

整數類型

在這裏插入圖片描述
INT 有 8 種類型,不一樣的類型的最大存儲範圍是不同的。

性別?用 TINYINT,由於 ENUM 也是整型存儲。

字符類型

變長狀況下,varchar 更節省空間,可是對於 varchar 字段,須要一個字節來記錄長度。

固定長度的用 char,不要用 varchar。

非空

非空字段儘可能定義成 NOT NULL,提供默認值,或者使用特殊值、空串代替 null。

NULL 類型的存儲、優化、使用都會存在問題。

不要用外鍵、觸發器、視圖

下降了可讀性;

影響數據庫性能,應該把把計算的事情交給程序,數據庫專心作存儲;

數據的完整性應該在程序中檢查。

大文件存儲

不要用數據庫存儲圖片(好比 base64 編碼)或者大文件;

把文件放在 NAS 上,數據庫只須要存儲 URI(相對路徑),在應用中配置 NAS 服務器地址。

表拆分

將不經常使用的字段拆分出去,避免列數過多和數據量過大。

好比在業務系統中,要記錄全部接收和發送的消息,這個消息是 XML 格式的,用 blob 或者 text 存儲,用來追蹤和判斷重複,能夠創建一張表專門用來存儲報文。

後話

MySQL 專題到這個篇章就正式結束了,基本上是按照腦圖的方向來,因此你們能夠對着腦圖以及個人博文來進行 MySQL 的複習,基本上面試的問題都有涉及,編寫一個專題確實是費腦又費精力費時間的事情,我仍是須要你們的關注和點贊來支撐一下哈哈哈~

若是你們以爲寫得還有點東西的話幫忙關注一下個人公衆號,而且在後臺給我留言但願我寫哪一個專題的東西(現學現賣的若是有什麼不對的地方也請幫忙指正,萬分感謝),人多的話立刻安排上~

仍是那樣,修整一段時間後會先在公衆號推送腦圖,而後根據腦圖來擬專題的提綱,這樣我寫得不會雲裏霧裏,你們也會比較有方向地看個人博文,再次感謝你們的支持~

By the way

有問題?能夠給我留言或私聊 有收穫?那就順手點個讚唄~

固然,也能夠到個人公衆號下「6曦軒」,

回覆「學習」,便可領取一份 【Java工程師進階架構師的視頻教程】~

回覆「面試」,能夠得到: 【本人嘔心瀝血整理的 Java 面試題】

回覆「MySQL腦圖」,能夠得到 【MySQL 知識點梳理高清腦圖】

因爲我咧,科班出身的程序員,php,Android以及硬件方面都作過,不過最後仍是選擇專一於作 Java,因此有啥問題能夠到公衆號提問討論(技術情感傾訴均可以哈哈哈),看到的話會盡快回復,但願能夠跟你們共同窗習進步,關於服務端架構,Java 核心知識解析,職業生涯,面試總結等文章會不按期堅持推送輸出,歡迎你們關注~~~

在這裏插入圖片描述
相關文章
相關標籤/搜索