MySQl的一些基本知识(1)
MySQL優(yōu)化
數(shù)據(jù)庫優(yōu)化維度有四個: 硬件、系統(tǒng)配置、數(shù)據(jù)庫表結(jié)構(gòu)、SQL及索引 優(yōu)化成本: 硬件>系統(tǒng)配置>數(shù)據(jù)庫表結(jié)構(gòu)>SQL及索引 優(yōu)化效果: 硬件<系統(tǒng)配置<數(shù)據(jù)庫表結(jié)構(gòu)<SQL及索引
運行機(jī)制原理和底層架構(gòu)
MySQL的查詢優(yōu)化,大家都了解一些最簡單的技巧:不能使用SELECT *、不使用NULL字段、合理創(chuàng)建索引、為字段選擇合適的數(shù)據(jù)類型….. 你是否真的理解這些優(yōu)化技巧?是否理解其背后的工作原理?在實際場景下性能真有提升嗎?我想未必。因而理解這些優(yōu)化建議背后的原理就尤為重要
1.MySQL邏輯架構(gòu)
-
最上層為客戶端層,并非MySQL所獨有,諸如:連接處理、授權(quán)認(rèn)證、安全等功能均在這一層處理
-
中間這一層,包括查詢解析、分析、優(yōu)化、緩存、內(nèi)置函數(shù)(比如:時間、數(shù)學(xué)、加密等函數(shù))。所有的跨存儲引擎的功能也在這一層實現(xiàn):存儲過程、觸發(fā)器、視圖等
-
第三層包括了存儲引擎。通常叫做StorEngine Layer ,也就是底層數(shù)據(jù)存取操作實現(xiàn)部分,由多種存儲引擎共同組成。它們負(fù)責(zé)存儲和獲取所有存儲在MySQL中的數(shù)據(jù)。就像Linux眾多的文件系統(tǒng) 一樣。每個存儲引擎都有自己的優(yōu)點和缺陷
2. MySQL邏輯模塊組成
從上圖看起來 MySQL 架構(gòu)非常的簡單,就是簡單的兩部分而已,但實際上每一層 中都含有各自的很多小模塊,尤其是第二層 SQL Layer ,結(jié)構(gòu)相當(dāng)復(fù)雜的
Connectors
指的是不同語言中與SQL的交互的接口,包括python,php,nodejs,java
Management Serveices & Utilities
系統(tǒng)管理和控制工具,包括mysql的配置,權(quán)限,日志處理等
Connection Pool: 連接池
管理緩沖用戶連接,線程處理等需要緩存的需求,。每一個連接上 MySQL Server 的客戶端請求都會被分配(或創(chuàng)建)一個連接線程為其單獨服務(wù)。而連接線程的主要工作就是負(fù)責(zé) MySQL Server 與客戶端的通信
SQL Interface: SQL接口
接受用戶的SQL命令,并且返回用戶需要查詢的結(jié)果。比如select from就是調(diào)用SQL Interface
Parser: 解析器
SQL命令傳遞到解析器的時候會被解析器驗證和解析,將SQL語句進(jìn)行語義和語法的分析,分解成數(shù)據(jù)結(jié)構(gòu),然后按照不同的操作類型進(jìn)行分類,然后做出針對性的轉(zhuǎn)發(fā)到后續(xù)步驟,如果在分解構(gòu)成中遇到錯誤,那么就說明這個sql語句是不合理的
Optimizer: 查詢優(yōu)化器
SQL語句在查詢之前會使用查詢優(yōu)化器對查詢進(jìn)行優(yōu)化。就是優(yōu)化客戶端請求的 query(sql語句) ,根據(jù)客戶端請求的 query 語句,和數(shù)據(jù)庫中的一些統(tǒng)計信息,在一系列算法的基礎(chǔ)上進(jìn)行分析,得出一個最優(yōu)的策略,告訴后面的程序如何取得這個 query 語句的結(jié)果
Cache和Buffer: 查詢緩存
他的主要功能是將客戶端提交 給MySQL 的 Select 類 query 請求的返回結(jié)果集 cache 到內(nèi)存中,在解析查詢之前,要查詢緩存,這個緩存只能保存查詢信息以及結(jié)果數(shù)據(jù)。如果請求一個查詢在緩存 中存在,就不需要解析,優(yōu)化和執(zhí)行查詢了。直接返回緩存中所存放的這個查詢的結(jié)果
存儲引擎接口
存儲引擎接口模塊可以說是 MySQL 數(shù)據(jù)庫中最有特色的一點了。目前各種數(shù)據(jù)庫產(chǎn)品中,基本上只有 MySQL 可以實現(xiàn)其底層數(shù)據(jù)存儲引擎的插件式管理
索引底層實現(xiàn)原理
MySQL官方對索引的定義為:索引(Index)是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。提取句子主干,就可以得到索引的本質(zhì):索引是數(shù)據(jù)結(jié)構(gòu)
B樹
B樹事實上是一種平衡的多叉查找樹,也就是說最多可以開m個叉(m>=2),我們稱之為m階b樹
-
每個節(jié)點至多可以擁有m棵子樹。
-
根節(jié)點,只有至少有2個節(jié)點(要么極端情況,就是一棵樹就一個根節(jié)點,單細(xì)胞生物,即是根,也是葉,也是樹)。
-
非根非葉的節(jié)點至少有的Ceil(m/2)個子樹(Ceil表示向上取整,圖中5階B樹,每個節(jié)點至少有3個子樹,也就是至少有3個叉)。
-
非葉節(jié)點中的信息包括[n,A0,K1,A1,K2,A2,…,Kn,An],,其中n表示該節(jié)點中保存的關(guān)鍵字個數(shù),K為關(guān)鍵字且Ki<Ki+1,A為指向子樹根節(jié)點的指針。
-
從根到葉子的每一條路徑都有相同的長度,也就是說,葉子節(jié)在相同的層,并且這些節(jié)點不帶信息,實際上這些節(jié)點就表示找不到指定的值,也就是指向這些節(jié)點的指針為空
MyISAM索引的原理圖
-
MyISAM引擎使用B+Tree作為索引結(jié)構(gòu),葉節(jié)點的data域存放的是數(shù)據(jù)記錄的地址
InnoDB索引的原理圖
-
在InnoDB中,表數(shù)據(jù)文件本身就是按B+Tree組織的一個索引結(jié)構(gòu),這棵樹的葉節(jié)點data域保存了完整的數(shù)據(jù)記錄
了解不同存儲引擎的索引實現(xiàn)方式對于正確使用和優(yōu)化索引都非常有幫助,例如知道了InnoDB的索引實現(xiàn)后,就很容易明白為什么不建議使用過長的字段作為主鍵,因為所有輔助索引都引用主索引,過長的主索引會令輔助索引變得過大。再例如,用非單調(diào)的字段作為主鍵在InnoDB中不是個好主意,因為InnoDB數(shù)據(jù)文件本身是一棵B+Tree,非單調(diào)的主鍵會造成在插入新記錄時數(shù)據(jù)文件為了維持B+Tree的特性而頻繁的分裂調(diào)整,十分低效,而使用自增字段作為主鍵則是一個很好的選擇
explain參數(shù)詳解
查詢語句是我們在使用MySQL的頻率最高的語句,也是影響性能最重要的環(huán)節(jié),我們用explain這個命令來查看一個這些SQL語句的執(zhí)行計劃和查詢效率,該命令從SQL執(zhí)行的執(zhí)行順序,執(zhí)行效率,索引使用情況等方面都給出了相應(yīng)的標(biāo)準(zhǔn),讓我們有據(jù)可查。
-
SQL語句編寫流程
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 > -
SQL執(zhí)行流程
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> -
使用方式
explain select * from uek_table; -
執(zhí)行效果
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
| id | select_type | table ? ? | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE ? ? | uek_table | ALL | NULL ? ? ? ? | NULL | NULL ? | NULL | ? 1 | NULL |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
row in set (0.03 sec)
案例代碼
```# 信息表
create table if not exists info(
id int(10) auto_increment primary key,
con varchar(100) not null)default charset=utf8;
?
# 老師表
create table if not exists teach(
id int(10) auto_increment primary key,
tname varchar(20) not null,
iid int(10),
CONSTRAINT infoid foreign key (iid) REFERENCES info(id)
)default charset=utf8;
?
?
# 課程表
create table if not exists course(
id int(10) auto_increment primary key,
cname varchar(20) not null,
tid int(10),
CONSTRAINT teachid foreign key (tid) REFERENCES teach(id)
)default charset=utf8;
?
```
1. id
id是SQL執(zhí)行的順序的標(biāo)識
-
id相同時,執(zhí)行順序由上至下(由于表的數(shù)據(jù)量的大小決定執(zhí)行順序)
-
如果是子查詢,id的序號會遞增,id值越大優(yōu)先級越高,越先被執(zhí)行
-
id如果相同,可以認(rèn)為是一組,從上往下順序執(zhí)行;在所有組中,id值越大,優(yōu)先級越高,越先執(zhí)行
2. select_type
查詢中每個select子句的類型
SIMPLE(簡單SELECT,不使用UNION或子查詢等)
PRIMARY(查詢中若包含任何復(fù)雜的子部分,最外層的select被標(biāo)記為PRIMARY)
UNION(UNION中的第二個或后面的SELECT語句)
DEPENDENT UNION(UNION中的第二個或后面的SELECT語句,取決于外面的查詢)
UNION RESULT(UNION的結(jié)果)
SUBQUERY(子查詢中的第一個SELECT)
DEPENDENT SUBQUERY(子查詢中的第一個SELECT,取決于外面的查詢)
DERIVED(派生表的SELECT, FROM子句的子查詢)
select form.cname from (select * from course where tid in (1,2)) as form3. table
顯示這一行的數(shù)據(jù)是關(guān)于哪張表的,看到的是derivedx的,說明這個結(jié)果是派生表的結(jié)果
4. type
表示MySQL在表中找到所需行的方式,又稱“訪問類型”,代表性能的優(yōu)劣 常用的類型有: ALL<index<range<ref<eq_ref<const<system<NULL
-
ALL:Full Table Scan, MySQL將遍歷全表以找到匹配的行,并且查找的內(nèi)容不帶索引
-
index: Full Index Scan,index與ALL區(qū)別為index類型只遍歷索引樹,也就是查找有索引的列
-
range:只檢索給定范圍的行,查找的內(nèi)容不帶索引,選擇的行帶索引,可以用between,>,<,但是不要用in,用in索引失效
-
ref: 表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值,使用普通索引
-
eq_ref: 類似ref,區(qū)別就在使用的索引是唯一引,對于每個索引鍵值,表中只有一條記錄匹配,簡單來說,就是多表連接中使用primary key或者 unique key作為關(guān)聯(lián)條件
-
const、system: 當(dāng)MySQL對查詢某部分進(jìn)行優(yōu)化,并轉(zhuǎn)換為一個常量時,使用這些類型訪問。如將主鍵置于where列表中,MySQL就能將該查詢轉(zhuǎn)換為一個常量。
-
system: 在衍生查詢中只有一條數(shù)據(jù)
select form.cname from (select cname from course where id=1) as form
5. possible_keys
MySQL預(yù)測使用哪個索引在表中查找記錄,如果是NULL說明MySQL找不到要使用的索引
6. Key
key列顯示MySQL實際決定使用的鍵(索引),如果鍵是NULL,說明該語句性能堪憂,根據(jù)實際使用場景要添加索引,經(jīng)常用來判斷復(fù)合索引是否完整使用
7. key_len
表示索引中使用的字節(jié)數(shù),可通過該列計算查詢中使用的索引的長度,不損失精確性的情況下,長度越短越好,尤其是使用InnoDB引擎
8. ref
表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值,如果是 const的話說明效率較高
```select cname from course where id=1
```
9. rows
表示MySQL根據(jù)表統(tǒng)計信息及索引選用情況,估算的找到所需的記錄所需要讀取的行數(shù)
10. Extra
該列包含MySQL解決查詢的詳細(xì)信息,有以下幾種情況:
-
Using index:指定索引的索引全部覆蓋,代表性能不錯
-
Using where:代表語句性能一般,僅僅從where指定的索引不能找到全部信息,需要回表查詢
-
Using temporary:表示MySQL需要使用臨時表來存儲結(jié)果集,常見于排序和分組查詢,說明在查詢中需要用臨時表存儲,性能消耗較大,常見于在一個沒有索引的表中進(jìn)行運算
explain select distinct name from abc; -
Using filesort:MySQL進(jìn)行了多次排序,沒有利用索引進(jìn)行排序,說明性能很低
創(chuàng)建一個復(fù)合索引的表
create table demo(
id int(10) auto_increment primary key,
one varchar(100),
two varchar(100),
three varchar(100),
index one (one),
index two (two),
index three (three)
)
?
創(chuàng)建sql語句
select * from demo where one="" order by one
select * from demo where one="" order by two1. 對于單索引查找,排序不是同一個索引會出現(xiàn)重新排序。2.對于復(fù)合索引要遵循最佳左前綴,不要跨列
-
Using join buffer:改值強(qiáng)調(diào)了在獲取連接條件時沒有使用索引,并且需要連接緩沖區(qū)來存儲中間結(jié)果。如果出現(xiàn)了這個值,那應(yīng)該注意,說明你的sql語句寫的太差了,需要mysql給你進(jìn)行優(yōu)化了,常見多表關(guān)聯(lián)。
-
Impossible where:這個值強(qiáng)調(diào)了where語句會導(dǎo)致沒有符合條件的行。
select * from demo where id=1 and id=2;
mysql優(yōu)化方法
1. 優(yōu)化工具
通過使用 explain命令分析sql語句的運行效率(查閱 explain章節(jié))
通過開啟慢查詢來查看運行效率慢的sql語句 (查閱日志章節(jié))
2. 索引優(yōu)化
索引是我們提升sql查詢效率的重要手段,同時索引的使用不當(dāng)也會帶來性能的問題,在使用索引的時候,應(yīng)該注意一下問題
不能將索引用作表達(dá)式的一部分,也不能是函數(shù)的參數(shù)
select * from demo where id+1=2?
select max(id) from demo where id=1;
索引不要進(jìn)行類型轉(zhuǎn)化,否則索引失效
select * from demo where name=2# 如果name是字符串類型,就存在類型轉(zhuǎn)換
復(fù)合索引應(yīng)該遵循左前綴策略,不要交叉使用
alter table table_name add index a_b_c (a,b,c)?
select c from table_name where id=a order by b
復(fù)合索引如果用"or"關(guān)鍵字,索引失效
select * from table_name where a="" or b=""復(fù)合索引不要使用 != <> 或 is null (is not null)
select * from table_name where a!=""盡量不要和in在一起使用,導(dǎo)致索引失效
select * from table_name where id in ("","")及時刪除冗余的和長期不使用的索引
like 查詢時候盡量不要出現(xiàn)左 "%",否則索引失效,如果非得使用,請用索引覆蓋提高性能,要使用獨立索引,不要使用復(fù)合索引
select * from table_name where con like "%內(nèi)容%"3. 單、多表SQL優(yōu)化手段
單表案例
有一個表用來記錄書籍的名字(bookname),出版號(publicid),作者(authorid),類型(typeid)。 然后查詢其中兩種類型并且屬于同一個作者,然后按照出版號來進(jìn)行排序
create table book(id int(10) auto_increment primary key,bookname varchar(100) not null,authorid varchar(20) not null,publicid int(10) default 11111,typeid int(10)) default charset=utf8;select * from book where typeid in(1,2) and authorid=1 order by publicid;-
加索引(并且加在頻繁使用的字段上)
-
調(diào)整索引順序(遵循最佳左前綴)
-
刪除多于(干擾)索引
-
調(diào)整查詢條件,對索引有干擾的語句放到條件的最后
多表案例
有一個試題類型表(testtype)記錄了試題的類型,字段包含 tid ,試題類型名稱 (name) 有一個試題內(nèi)容表(testcon)記錄了試題的題目(title),選項(opts),答案(result)和類型(tid)
# 類型表create table testtype(tid int(5) auto_increment primary key,name varchar(100))default charset=utf8;# 內(nèi)容表create table testcon(id int(5) auto_increment primary key,title varchar(100) not null,opts varchar(200) not null,result varchar(100) not null,tid int(5),CONSTRAINT testid foreign key (tid) REFERENCES testtype(tid))default charset=utf8;-
多表索引添加原則,小表驅(qū)動大表(小表在左邊 where 小表.x=大表.y)
-
left join 給左表加索引,right join 給右邊加索引
4. 表級別鎖優(yōu)化(查閱鎖章節(jié))
5. 系統(tǒng)級別優(yōu)化
主從復(fù)制
讀寫分離
負(fù)載均衡
6. 其他優(yōu)化總結(jié)
通常來說把可為NULL的列改為NOT NULL不會對性能提升有多少幫助,只是如果計劃在列上創(chuàng)建索引,就應(yīng)該將該列設(shè)置為NOT NULL
對于數(shù)據(jù)類型,一定要根據(jù)業(yè)務(wù)需求選擇盡可能小的存儲數(shù)據(jù)類型
UNSIGNED表示不允許負(fù)值,大致可以使正數(shù)的上限提高一倍,如果表示的是正數(shù),那么要用非符號
通常來講,沒有太大的必要使用DECIMAL數(shù)據(jù)類型。即使是在需要存儲財務(wù)數(shù)據(jù)時,仍然可以使用BIGINT。
TIMESTAMP使用4個字節(jié)存儲空間,DATETIME使用8個字節(jié)存儲空間
大多數(shù)情況下沒有使用枚舉類型的必要
表的列不要太多,如果列太多而實際使用的列又很少的話,有可能會導(dǎo)致CPU占用過高
轉(zhuǎn)載于:https://www.cnblogs.com/niupeinan/p/10554931.html
總結(jié)
以上是生活随笔為你收集整理的MySQl的一些基本知识(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TJOI2018Party
- 下一篇: 最大连续子序列----DP动态规划