Mysql知識梳理

Mysql知識梳理

數據類型

// todomysql

存儲引擎

InnoDB

  • InnoDB是是Mysql默認的事務性存儲引擎
  • InnoDB纔有MVCC來支持高併發,而且實現了四個標準的隔離級別,默認級別是可重複讀
  • InnoDB存儲引擎下的表是基於聚簇索引創建的,對主鍵的查詢性能有很高的提高

MyISAM

  • 提供了大量的特性,包括全文索引、壓縮、空間函數等
  • 不支持事物和行級鎖

InnoDB與MyISAM的比較

InnoDB:支持事物、在線熱備份、行鎖
MyISAM:支持全文索引、地理空間索引算法

索引

索引是幫助MySQL高效獲取數據的數據結構,因此索引本質上是一種數據結構

索引分類

  • B-Tree索引
    B-Tree索引是大多數Mysql存儲引擎默認的索引類型
    使用B-Tree索引後,不用再進行全表掃描,只須要對樹進行搜索便可,所以查找速度會快不少
    能夠指定多個列做爲索引列,多個索引列共同組成鍵
    B-Tree 索引適用於全鍵值、鍵值範圍和鍵前綴查找,其中鍵前綴查找只適用於最左前綴查找
    除了用於查詢,還能夠用於排序和分組
  • 哈希索引
    基於哈希表的實現,優勢是查詢很是快
    在Mysql中只有Memory存儲引擎支持哈希索引
  • 空間索引(R-Tree)
    MyISAM存儲引擎支持空間索引,能夠用於地理數據存儲
  • 全文索引
    MyISAM存儲引擎支持全文索引,用於查找文本中的關鍵字,而不是直接比較索引中的值

索引的優勢

  • 加快數據查詢方式,提升數據庫查詢性能
  • 大大減小了服務器須要掃描的數據量
  • 幫助服務器避免進行排序和建立臨時表
  • 將隨機 I/O 變爲順序 I/O

索引的缺點

  • 實際上索引也是一張表,該表保存了主鍵與索引字段,並指向實體表的記錄,因此索引列也是要佔用空間的。
  • 雖然索引大大提升了查詢速度,同時卻會下降更新表的速度,如對錶進行insert,update和delete。由於更新表時,MySQL不只要保存數據,還要保存一下索引文件每次更新添加索引列的字段,都會調整由於更新所帶來的鍵值變化後的索引信息。
  • 索引只是提升效率的一個因素,若是你的MySQL有大數據量的表,就須要花時間 研究創建最優秀的索引,或優化查詢語句。

建立索引的兩種方式

  • create indexsql

    CREATE INDEX index_name ON table_name (column_list)
  • alter table數據庫

    ALTER TABLE `table_name` ADD INDEX index_name (column_list)

操做索引

以articles的type字段爲例安全

-- 建立索引
CREATE INDEX idx_type ON articles (type);

-- 刪除索引
drop index idx_type on articles

-- 查看索引
show index from articles

使用索引的時機

通常狀況下,在where或join子句中出現的列須要添加索引。可是,由於MySQL只對<,<=,=,>,>=,between,in,以及某些時候的like纔會使用索引(使用like時,以通配符%_查詢時,MySQL不會使用索引)性能優化

  1. 哪些狀況下須要建立索引服務器

    • 主鍵自動創建惟一索引
    • 頻繁做爲查詢條件的字段應該建立索引
    • 查詢中與其餘表關聯的字段,外鍵關係創建索引
    • 單鍵/組合索引的選擇問題(在高併發下傾向組合索引)
    • 查詢中排序的字段,排序字段經過索引去訪問將大大提升排序速度
    • 查詢中統計或分組字段
  2. 哪些狀況下不須要建立索引數據結構

    • 表記錄太少,網上有建議2000爲界限,2000如下不建立
    • 常常增刪改的表(由於每次增刪改不只要操做數據還要操做索引)
    • where條件用不到的字段
    • 數據重複且分佈平均的字段,索引的選擇性較低,即當前字段不重複的索引值與表中當前字段的記錄數比值,值越大越不建議建索引

建立索引技巧

  • 給維度高的列建立索引併發

    • 數據列中不重複值出現的個數,數量越高,維度越高
    • 重複數據會下降維度
    • 給緯度高的列建立索引,好比用戶表的年齡維度就高於性別
    • 性別這種低緯度的列不適合建索引
  • 對where,on,group by,order by中出現的列使用索引
  • 對較小的數據列使用索引,這樣會使索引文件更小,同時內存中也能夠裝載更多的索引建
  • 爲較長的字符串使用前綴索引
  • 不要過多建立索引,過多的索引會增長額外的磁盤空間,對DML操做速度影響很大,由於每增刪改查一次就得從新創建索引
  • 使用組合索引,能夠減小文件索引大小,在使用時速度要優於多個單列索引

使用索引的注意事項

  • 索引不會包含有Null值的列,因此咱們在數據庫設計時不要讓字段的默認值爲NULL
  • 使用短索引數據庫設計

    • 對字符串列進行索引,若是可能應該指定一個前綴長度
  • 索引列排序

    • MySQL查詢只使用一個索引,所以若是where子句中已經使用了索引的話,那麼order by中的列是不會使用索引的。所以數據庫默認排序能夠符合要求的狀況下不要使用排序操做;儘可能不要包含多個列的排序,若是須要最好給這些列建立複合索引。
  • 不在索引列進行運算操做
  • 建組合索引的時候,區分度最高的在最左邊

索引優化

  • 獨立的列

    在查詢時,索引不能是表達式的一部分,也不能是函數的參數,不然沒法使用索引
  • 前綴索引

    對於blob,text,varchar類型的列,必須使用前綴索引,只索引開始的部分字符
  • 多列索引

    在須要使用多個列做爲條件查詢時,使用多列索引比使用單列索引性能要好
  • 索引列的順序

    在寫查詢語句時,將選擇性強的列放在前面

join語句的優化

left join是由左邊決定的,左邊必定都有,因此右邊是咱們的關鍵點,創建索引要建右邊的。固然若是索引在左邊,能夠用右鏈接。
儘量減小Join語句中的NestedLoop的循環次數:「永遠用小結果集驅動大的結果集」

避免索引失效

  1. 最佳左前綴法則:若是查詢中使用了多個索引列,要遵循最左前綴法則,指的是查詢從索引的最左前列開始而且不跳過索引中列。
  2. 不在索引列上作任何操做(計算、函數、(自動/手動)類型轉換),會致使索引失效而轉向全表掃描。
  3. where條件的列=的判斷放在比較運算符><等的左邊,放在比較運算符右邊的索引會失效
    好比:

    select * from user where username="saboran" and age > 18 and mobile = "18862612345"

    其中username、age、mobile都有索引,可是隻有username和age的索引會生效,mobile索引用不到

  4. select查詢時儘可能減小select * 操做,用須要的字段代替*
  5. 在使用!=或者<>的時候沒法使用索引,會致使全表掃描
  6. is null 和 is not null 也沒法使用索引
  7. like 以通配符開頭,mysql索引會失效變成全表掃描
    因此最好用右邊通配符匹配like 'tssk%'
    若是要使用兩邊通配符匹配,則將like條件放在最後一個
    好比:

    select age from users where a = 3 and b = 4 and c like "%abcd%";

    這樣a、b、c都有索引的話,a、b用的上,c用不上

  8. 字符串不加單引號索引會失效
  9. 少用or,用它鏈接時會索引失效
  10. 避免子查詢,使用join

通常性建議

  1. 對於單鍵索引,儘可能選擇針對當前查詢語句過濾性更好的索引做爲查詢條件
  2. 在選擇組合索引時,當前query中過濾性最好的索引放在where條件的位置越靠前越好
  3. 儘量經過分析統計信息和調整query的寫法來達到選擇合適索引的目的

查詢性能優化

Explain

用來分析SQL語句,分析結果中比較重要的字段有:

  • select_type:查詢類型,有簡單查詢、聯合查詢和子查詢
  • key:使用的索引
  • rows:掃描的行數

減小返回的列

慢查詢主要是由於訪問了過多數據,除了訪問過多行以外,也包括訪問了過多列。最好不要使用select * 語句,要根據須要選擇查詢的列

減小查詢的行

最好使用limit語句取出想要的那些行,還能夠創建索引來減小條件語句的全表掃描

經常使用函數

數學函數

  • ABS(x) // 返回x的絕對值

    select abs(age) from users limit 1; -- 18
  • BIN(x) // 返回x的二進制數

    select bin(age) from users limit 1; -- 10010
  • CEILING(x) // 返回大於x的最小整數值

    SELECT CEILING (19.1) ; -- 20
  • FLOOR(x) // 返回小於x的最大值

    SELECT floor (19.1) ; -- 19
  • RAND() // 返回0到1的隨機數

    SELECT rand() ; -- 0.8320153586864615  隨機數
  • ROUND(x,y) // 返回參數x的四捨五入的y位小數值

    SELECT ROUND(100.123456,3); -- 100.123

聚合函數(經常使用與group by從句的select查詢中)

  • AVG(col) // 返回指定列的平均數

    select avg(age) from users ; -- 14.0000
  • COUNT(col) // 返回指定列中非null值的個數

    SELECT count(id) from users ; -- 2
  • MIN(col) // 返回指定列的最小值

    select min(age) from users ; -- 10
  • MAX(colcol) // 返回指定列的最大值

    select max(age) from users ; -- 18
  • SUM(col) // 返回指定列全部值的和

    select sum(age) from users ; -- 28
  • GROUP_CONCAT(col) // 返回由屬於一組的列值鏈接組合而成的結果

    select GROUP_CONCAT(age) from users ; -- 18,20

字符串函數

  • CONCAT(s1,s2,s3,sn) // 將s1,s2,s3,sn鏈接爲字符串

    select CONCAT(id,age,name) from users limit 1; -- 118安小下
  • CONCAT_WS('|') // 將s1,s2,s3,sn鏈接爲字符串,並使用|分隔,|能夠替換爲任意分隔符

    SELECT CONCAT_WS('|',id,name,age) from users limit 1; -- 1|安小下|18

日期和時間函數

  • CURDATE()/CURRENT_DATE() // 返回當前日期

    SELECT CURRENT_DATE(); -- 2018-03-08
  • CURTIME()/CURRENT_TIME() // 返回當前時間

    SELECT CURRENT_TIME(); -- 08:54:15
  • DATE_FORMAT(date,fmt) // 按照fmt格式,格式化date

    SELECT DATE_FORMAT(CURRENT_DATE(),'%Y/%m/%d'); -- 2018/03/08
  • DAYOFWEEK(date) // 返回date爲一週以內的第幾天,從0開始,0表明第一天

    SELECT DAYOFWEEK(CURRENT_DATE()); -- 5
  • DAYOFMONTH(date) // 返回date爲一月以內的第幾天

    SELECT DAYOFMONTH(CURRENT_DATE()); -- 8
  • DAYOFYEAR(date) // 返回date爲一年以內的第幾天

    SELECT DAYOFYEAR(CURRENT_DATE()); -- 67
  • DAYNAME(date) // 返回date的星期名

    SELECT DAYNAME(CURRENT_DATE()); -- Thursday
  • FROM_UNIXTIME(timestimps,fmt) // 時間戳轉成fmt格式的字符串時間

    SELECT FROM_UNIXTIME(1520500384,"%Y/%m/%d"); -- 2018/03/08
  • HOUR(time) // 返回time的小時值(0-23)

    SELECT HOUR('20:10'); -- 20
  • MINUTE(time) // 返回time的分鐘值(0-59)

    SELECT HOUR('20:10'); -- 10
  • MONTH(date) // 返回date的月份值(1-12)

    SELECT MONTH(CURRENT_DATE()); -- 3
  • MONTHNAME(date) // 返回date的月份名

    SELECT MONTHNAME(CURRENT_DATE()); -- March
  • NOW() // 獲取當前日期和時間

    SELECT NOW(); -- 2018-03-08 09:26:55
  • WEEK(date) // 返回日期date爲一年中的第幾周

    SELECT WEEK(CURDATE()); -- 9
  • YEAR(date) // 返回日期date的年份

    SELECT YEAR(CURDATE()); -- 2018

加密函數

  • MD5(str) // 計算字符串str的MD5檢驗值
  • PASSWORD(str) // 返回字符串str的加密版本,這個加密是不可逆的
  • SHA(str) // 計算字符串str的安全散列算法檢驗值

控制流程函數

// todo

格式化函數

  • INET_ATON(ip) // 返回ip表明額數字
  • INET_NTOA(num) // 返回數字表明的ip

Distinct去重

單獨的distinct只能放在開頭
-- 會報錯
select id,DISTINCT(name) from test;

-- 不會報錯
select DISTINCT(name) from test;
相關文章
相關標籤/搜索