爲甚是使用索引
索引的結構
使用b+tree實現php
mysql爲何使用b+tree?
Myisam
數據和索引分別存儲, 索引文件中的葉子節點, 保存的是數據的引用地址;
innerDB
1. 只有一個文件, 索引和數據放在同一個文件中; 2. 以主鍵爲索引來組織存儲數據的; 3. 而且主鍵索引使用的是彙集索引(數據存儲的順序和索引的邏輯順序); 4. 其餘索引的葉子節點實際存儲的是主鍵的值, 查找時在會主鍵存儲查找一次;
存儲引擎分類 a). csv: 使用於數據的導入導出, 表格直接轉化成csv文件; b). archive: 只容許insert和select, id只能自增, 不支持事務, 行級鎖, 可是數據佔用空間小, 適用於日誌採集; c). memory: 數據存儲在內存中, io效率高, 安全性低, d). myisam: 不支持事務, 表級鎖, 自動存儲count, 索引的存儲結構, 主要適用於大量讀, 少許寫的場景; e). innerDB: 支持事務, 行級鎖, 主鍵索引, 對數據安全性要求較高的場景;
查詢命令 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相同時, 由上向下; 不一樣時, 值越大的先被執行;
system: 表中只有一行記錄, const的特例, 基本不會出現; const: 只查到一條數據的查詢, 經常使用在主鍵索引和惟一索引上; eq_ref: 查詢時, 每一個查詢條件只有一條記錄和他匹配; ref: 每一個查詢可能會有多條和他匹配, 常見於主鍵或者惟一索引; range: 範圍查詢 index: 索引的全表掃描; all: 不是用索引的全表掃描;
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
acid: 原子性, 隔離性, 一致性, 持久性;算法
隔離級別
innerDB在rr級別解決了幻讀的問題;鎖的使用sql
共享鎖: 多個事務可共用, 其餘事務只能讀不能寫; 使用方式: select * from xxx LOCK IN SHARE MODE; 排他鎖: 只能被一個事務持有的鎖; 使用方式: delete/update/insert默認加排他鎖, select * from xx FOR UPDATE; innerDB的行鎖鎖是經過給索引項加鎖實現的, 只有經過索引進行條 件檢索, 才能使用行鎖, 不然使用表鎖; innerDB默認使用臨建鎖(next-key)實現行鎖算法, 另外還有間隙鎖, 記錄鎖, 範圍查找並找到值時, 臨建鎖, 未找到值, 間隙鎖, 而精確查找並命中主鍵/惟一索引的時候, 是記錄鎖(詳情待補充);
主要爲了解決寫操做對讀操做的阻塞;
原理:數據庫
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, 這些都是當前讀;
前提是, 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, 而後後臺每秒提交一次; (提交說的是持久化磁盤)
全局參數和會話參數
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