Mysql筆記

mysql索引機制
爲甚是使用索引
  • 減小存儲引擎掃描的數據量;
  • 把隨機io轉化爲順序io;
  • 在分組和排序的時候, 避免使用臨時表;
索引的結構

使用b+tree實現php

  • 二叉樹: 存在的問題, 會造成鏈表的數據結構, 並且樹的層級太深的時候(io次數也會不少), 查詢效率也不高;
  • 平衡二叉樹: 主要的優勢是, 整個樹的高度差不會超過1, 能夠避免造成鏈表結構, 而且保證層級不會在某一側太深, 可是由於每一個節點保存的數據太少, 仍是會出現層級太深的問題;
  • B-Tree: 多路平衡查找樹, 顧名思義, 就是一個節點下存在多個分支, 能夠大大減小樹的高度, 而且每一個節點上行;
  • B+tree: 大致結構和b-tree相似, 可是b+tree非葉子節點不保存數據, 只保存關鍵字, 數據所有放在葉子節點中, 葉子節點的數據區是由順序的, 而且葉子節點之間有鏈表鏈接;
mysql爲何使用b+tree?
  1. 擁有b-tree的優點;
  2. 因爲每一個節點不保存數據只保存關鍵字, 所以, 他的掃表能力和磁盤的讀取能力更強;
  3. 數據保存在葉子節點, 而且順序存儲, 因此b+tree的排序能力更好;
mysql中的b+tree實現具體形式
Myisam
數據和索引分別存儲, 索引文件中的葉子節點, 保存的是數據的引用地址;
innerDB
1. 只有一個文件, 索引和數據放在同一個文件中;
2. 以主鍵爲索引來組織存儲數據的;
3. 而且主鍵索引使用的是彙集索引(數據存儲的順序和索引的邏輯順序);
4. 其餘索引的葉子節點實際存儲的是主鍵的值, 查找時在會主鍵存儲查找一次;
索引的其餘知識
  1. 列的離散性, 離散性越高, 選擇性越好, 離散性過低的可近似爲全表掃描了;
  2. 最左匹配原則: 查詢的時候是從左向右一個一個比對, 而且不能跳過;
  3. 最小空間原則: 空間最小原則;
  4. 覆蓋索引: sql查詢的列能夠經過索引的關鍵字直接返回, 則稱之爲覆蓋索引;
  5. like 'xxx%'不必定用到索引;
  6. age > 22 and name = 'xxx', 若是是聯合索引的話, 只有前面一條能用到;
mysql總體架構

image.png

  1. 客戶端driver, 如java , php等;
  2. 接入方進入後, 交給connect pool管理(包括創建鏈接和安全認證);
  3. sql interface, 用來接收sql;
  4. parse, 根據sql規範來解析sql;
  5. optimize: sql優化器, 會將咱們的sql進行優化;
  6. cache: 緩存, 會緩存sql語句和查詢結果;
  7. 存儲引擎: 插拔式的存儲引擎;
存儲引擎分類
    a). csv: 使用於數據的導入導出, 表格直接轉化成csv文件;
    b). archive: 只容許insert和select, id只能自增, 不支持事務, 行級鎖, 
    可是數據佔用空間小, 適用於日誌採集;
    c). memory: 數據存儲在內存中, io效率高, 安全性低, 
    d). myisam: 不支持事務, 表級鎖, 自動存儲count, 索引的存儲結構, 主要適用於大量讀, 少許寫的場景;
    e). innerDB: 支持事務, 行級鎖, 主鍵索引, 對數據安全性要求較高的場景;
mysql的鏈接的狀態
  • sleep: 等待鏈接
  • query: 正在查詢
  • locked: 線程等待表鎖釋放
  • sorting result: 正在對結果進行排序
  • sending data: 向請求端返回數據
查詢命令 show full processlist
緩存的做用

查詢的時候先查緩存, 命中, 返回, 沒命中, 查詢磁盤, 而後保存進緩存中;java

#查看緩存參數
show variables like 'query_cache%'

query_cache_limit    1048576 #一次查詢最多緩存多少, 超過不緩存
query_cache_min_res_unit    4096
query_cache_size    0 #總的緩存的大小
query_cache_type    ON #是否開啓緩存, 0 不開啓, 1 開啓
query_cache_wlock_invalidate    OFF

設置值, set global query_cache_type = ..;
數據被增刪改的時候會刪除緩存;
查詢優化處理
規則
1. 等價查詢轉化: a < b and b = 5轉化爲a< 5 and b = 5;
2. 將可轉化的外連接轉化爲內鏈接;
3. 優化count, max, min等函數;
4. 覆蓋索掃描;
5. 子查詢優化;
6. 自動終止查詢, limit=1時, 再查到數據後不會繼續掃描;
7. in的優化, 會對in中數據進行二分查找, 因此用or的時候儘可能轉化爲in
...
鏈接查詢
1.內鏈接(天然鏈接):只有兩張表相匹配的行才能出如今結果集;
2.外鏈接包括:
    2.1 左外鏈接:左邊爲主表,左邊的表顯示所有;右邊爲副表,右邊無符號數據時顯示null,不符合的不顯示;
    2.2 右外鏈接:右邊爲主表,右邊的表顯示所有;左邊爲副表,左邊無符號數據時顯示null,不符合的不顯示;
執行計劃id
id相同時, 由上向下;
不一樣時, 值越大的先被執行;
select type
  • simple: 簡單的select查詢, 不包含子查詢和union查詢;
  • primary: 查詢中包含子查詢, 最外層的查詢時primary查詢;
  • subquery/materialize: subquery表示在select或where列表中包含了子查詢, meterialize表示where後面的in中的查詢;
  • union: 若第二個select出如今union以後, 爲union查詢;
  • union result: 從union表獲取結果的select
執行計劃type
system: 表中只有一行記錄, const的特例, 基本不會出現;
const: 只查到一條數據的查詢, 經常使用在主鍵索引和惟一索引上;
eq_ref: 查詢時, 每一個查詢條件只有一條記錄和他匹配;
ref: 每一個查詢可能會有多條和他匹配, 常見於主鍵或者惟一索引;
range: 範圍查詢
index: 索引的全表掃描;
all: 不是用索引的全表掃描;
extra
  • useing filesort: 進行了從新的排序, 若是命中索引, 則不會;
  • useing where: 進行了回標查詢;
  • useing temporary: 使用到了臨時表(例如group by時);
  • useing index: 用到了覆蓋索引(提升性能);
定位慢sql

show variables like 'slow_query_log';
set global ...='xxx';
show variables like 'slow_query%'; #能夠設置慢查詢日誌保存路徑
set global log_queries_not_using_indexes = on;#沒有命中索引的也記錄
set global long_query_time=0.1; #設置慢查詢時間mysql

mysql事務

acid: 原子性, 隔離性, 一致性, 持久性;算法

隔離級別
  • uncommited; 讀到其餘事務未提交數據;
  • commited: 連續兩次讀取同一數據不相同, 解決髒讀;
  • repeatable-read: 解決連續兩次同一數據讀取值不一樣問題;
  • serializable: 解決幻讀, 數據插入和刪除的問題;
innerDB在rr級別解決了幻讀的問題;

鎖的使用sql

  • 行鎖和表鎖的區別
    鎖定粒度, 加鎖效率, 衝突機率, 併發性能方面有區別;
  • innerDB支持行鎖和表鎖, 可是實現的前提是加索引;
  • 鎖類型
共享鎖: 多個事務可共用, 其餘事務只能讀不能寫;
    使用方式: select * from xxx LOCK IN SHARE MODE;
排他鎖: 只能被一個事務持有的鎖;
    使用方式: delete/update/insert默認加排他鎖, select * from 
    xx FOR UPDATE;
    
    innerDB的行鎖鎖是經過給索引項加鎖實現的, 只有經過索引進行條
    件檢索, 才能使用行鎖, 不然使用表鎖;
innerDB默認使用臨建鎖(next-key)實現行鎖算法, 另外還有間隙鎖, 記錄鎖, 範圍查找並找到值時, 臨建鎖, 未找到值, 間隙鎖, 而精確查找並命中主鍵/惟一索引的時候, 是記錄鎖(詳情待補充);
MVCC多版本併發控制

主要爲了解決寫操做對讀操做的阻塞;
原理:數據庫

1. 數據庫中的每張表都會設置一列事務id(存儲數據建立時的id)和一列
刪除事務id(保存數據刪除時的id), 這個事務id是全局惟一的;
2. 數據建立時, 會獲取當前的事務id, 保存在事務id的列中, 刪除事務
id列爲空;
3. 數據刪除時, 獲取當前事務id, 保存在刪除事務id列中;
4. 數據更新時, 獲取當前事務id, 將原數據copy一份, 放入表中, 事務
id爲當前事務id, 刪除id置爲空, 原來的數據則將刪除id設置爲當前事務
id;
5. 查詢的時候, 會獲取事務id比當前事務id小(保證獲取的數據在本事務
開始以前就存在), 同時刪除事務id爲空或者比當前事務id大的數據(保證
獲取的數據是在當前事務以前沒刪除的);

上述過程若是是先查詢後更新, 是沒有問題的;
可是在先更新(但未提交)後查詢的時候是會出錯的;
解決辦法undo.log
使用undo.log, 在每一個事務開始的時候, mysql會備份一次老的數據, 存
在undo.log中, 這樣查詢的操做, 若是修改已經提交, 就查表, 若是未
提交, 就能夠直接去undo.log中查詢;

undo.log的做用:
1. 用於事務的rollback回滾;
2. 做爲數據的舊版本, 爲其餘併發事務提供快照讀;
快照讀
讀取歷史版本, innerdb的普通select語句都是快照讀, 讀取的數據有原
本數據和undo數據組成
當前度
讀取最新版本, 保證當前的數據不能被其餘事務修改, update/ delete/ insert/ select ... lock in share mode/ select ... for update, 這些都是當前讀;
Redo.log
前提是, innerDB不是每次的事務都會持久化到磁盤, 而是先保存在
緩存中, 在必定時間的時候一塊兒提交, 將事務更改的最新的數據放入
redo.log, 主要是爲了實現事務的持久性, 防止數據庫發生故障的
時候, 有未進行磁盤化的數據, 保存在redo.log中保證在mysql重啓
後, 能夠根據redo.log恢復已經提交的數據;

redo.log的其餘細節
1. redo.log日誌文件組中文件的個數默認innerdb_log_files_in_group=2;
2. 每一個日誌最大存儲量innordb_log_file_size=48M;
3. redo.log的緩存池大小innodb_log_buffer_size=16M;

Buffer持久化策略: innordb_flush_log_at_trx_commit
0: 每秒提交一次;
1. 每次事務提交, 提交一次;
2. 每次事務提交, 將redo buffer刷一次到os cache, 而後後臺每秒提交一次;
(提交說的是持久化磁盤)
mysql配置優化
全局參數和會話參數
set global ...是全局參數設置
set session ...是會話參數設置
注意:
    全局參數設置對已經存在的會話無效, 須要關閉會話從新鏈接;
    會話參數隨着會話結束會銷燬;
    全局參數若是服務器重啓, 也會銷燬, 最好配置在配置文件中;

查找my.cnf命令緩存

mysql --help
裏面注意的配置:
#最大鏈接配置數, 該這個參數的時候要注意兩個地方
#1. 系統句柄數, ulimit -a
#2. mysql句柄數配置 /usr/lib/systemd/system/mysqld.service
max_connections

mysql內存參數配置
    #每一個connection內存參數配置
    #排序緩衝區大小
    sort_buffer_size 建議2M之內;
    #關聯緩衝區大小
    join_buffer_size 1M之內;
    上述配置佔用內存計算: 4000*(0.256+0.256)
    
    #innerdb緩衝池大小, 大的緩衝區能夠減小網絡io(數據緩存, 索引緩存等)
    #計算公式 (總物理內存-系統運行內存-connection所用)*90%
    innerdb_buffer_pool_size
    
其餘參數配置
    #服務器關閉非活躍鏈接以前要等待多少秒
    wait_timeout
    #限制innordb能打開表的數量
    innordb_open_files
    #等待鎖的超時時間
    innordb_lock_wait_timeout

數據庫表設計也會影響性能安全

三範式以及字段設置爲not null
相關文章
相關標籤/搜索