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