此文章爲《深入淺出MySQL》第二版的備忘錄。
第2章 SQL基礎
SQL語句分爲:
- DDL(Data Definition Languages)語句: 數據庫結構定義爲語言。
- DML(Data Manipulation Languages)語句: 數據操作語句。
- DCL(Data Control Languages)語句: 權限控制語句。
MySQL自帶數據庫:
-
information_schema: 存儲數據庫對象信息,如用戶表,列,權限,字符集,分區等信息。此爲虛擬數據庫,其中的表均爲視圖。
- SCHEMATA: 當前mysql實例的所有數據庫信息,
show databases
信息來源。 - TABLES: 關於數據庫的表(視圖)信息,
show table from ${schame_name}
信息來源。 - COLUMNS:
show columns from ${schema_name}
.${table_name}
信息來源。 - STATISTICS: 表的索引信息。
show index from ${schema_name}
.${table_name}
信息來源。
- SCHEMATA: 當前mysql實例的所有數據庫信息,
- cluster: 存儲集羣信息。
- mysql: 存儲用戶權限信息。
- test: 系統自動創建的測試數據庫,任何用戶均可使用。
在MySQL世界,drop語句操作的結果都顯示 0 rows affected。
WITH ROLLUP可對分類聚合後的結果進行再彙總。
UNION於UNION ALL的區別是會進行一次DISTINCT操作。
? contents 或者 ? <key_words> 可快速查詢使用手冊。
第3章 數據類型
若列被指定了zerofill,則會自動添加UNSIGNED屬性。
DECIMAL默認爲DECIMAL(10, 0)
TIMESTAMP:
- 表中的第一個TIMESTAMP列的默認值將被設置爲當前時間。
- 其值的存儲與讀取與時區有關。
VARCHAR會保留存儲後端空格,CHAR不會。
第4章 運算符
<=>: NULL安全的等於, 也即:
- SELECT NULL <=> NULL return 1
- SELECT NULL = NULL return 0
第5章 常用函數
第7章 存儲引擎
MySQL默認引擎在5.5後更改爲InnoDB。
第8章 合適的數據類型
對於InnoDB,內部行存儲合適未區分可變長度和固定長度。故推薦使用VARCHAR,其平均空間佔用更小。
編程與存儲時,精確計算需使用定點數(Decimal,Java中也有此類),浮點數會有誤差。
對於BLOB和TEXT,刪除和修改操作後均需使用OPTIMIZE TABLE對錶進行碎片整理。
第9章 字符集
字符集選擇原則
- 多語言支持或主要處理英文字符,UTF8。
- 只需要支持中文,GBK,因其較小,每個中文佔用2個字節,UTF8爲3個。
- 需要做大量的字符計算,排序,比較等,建議定長字符。
- 考慮客戶端的字符集。
show character set或查看information_schema.character_set顯示所有的字符集(MySQL字符串的存儲方式)和該字符集對應的校對規則(比較字符串的方式),其爲一對多的關係。
show collation like *或者查看information_schema.COLLATIONS查看相關字符集的校對規則。
校對規則結尾命名:
- _ic: 大小寫不敏感。
- _cs: 大小寫敏感。
- _bin: 比較字符編碼值。
show variables like ‘character_set_${scope}’;
show variables like ‘collation_${scope}’;
查看當前scope(server: 服務器, database: 數據庫)的字符集和校對規則。
第10章 索引
索引列的數據越分散,篩選結果集越小,作用越大,比如對於性別列作用不大。
使用短索引。
利用最左前綴。
普通索引均會保存主鍵鍵值,故主鍵儘可能選擇較短的數據類型。
HASH索引於BTREE索引:
- 只能使用=和<=>進行匹配。
- 無法進行排序優化。
第11章 視圖
不可更新的視圖:
- 包含聚合函數(SUM, MIN, MAX, COUNT等),DISTINCT, GROUP BY, HAVING, UNION, UNION ALL語句。
- 常量視圖。
- SELECT包含子查詢。
- FROM一個不能更新的視圖。
- WHERE中的子查詢引用了FROM中的表。
WITH CASCADED | LOCAL CHECK OPTION: 滿足該視圖即可更新 | 滿足所有相關視圖纔可更新。
SHOW TABLE STATUS FROM DB LIKE PATTERN.
SHOW CREATE VIEW VIEW_NAME
information_schema.views
第12章 存儲過程和函數
創建二者需要CREATE ROUTINE權限,修改需要ALTER ROUTINE權限,執行需要EXECUTE權限。
DELIMITER $$可修改語句結束標示。
查看方式與VIEW的查看方式類似。
- 事件調度器
- 流程控制(IF, CASE, REPEAT等)
- 光標
- 條件和處理
- 變量
第13章 觸發器
第14章 事務控制與鎖定語句
(UN)LOCK TABLE.
事務控制中SAVEPOINT的使用。
分佈式事務命令XA,prepare狀態下出現異常,則 binlog不會存在記錄,會使數據不一致。數據完整性要求不高時可使用。
第15章 SQL中的安全問題
防止SQL注入:
- 對用戶輸入進行轉義,一般的ORM框架可實現。
- 使用數據庫提供的轉換函數,quote等。
- 代碼敏感字符攔截。
SQL MODE
不同嚴格程度SQL語法和數據校驗。
SQL_MODE的常見功能:
- ANSI和TRADITIONAL: 允許和不允許插入非法時間值,MOD(X, 0)等。
- NO_BACKSLASH_ESCAPES: 視 爲普通字符。
- PIPES_AS_CONCAT: 視 || 爲字符串連接符使其不報錯。
常用SQL_MODE:
- ANSI: 寬鬆模式。
- STRICT_TRANS_TABLE: 嚴格模式。
- TRADITIONAL: 嚴格中的嚴格模式。
第16章 SQL分區
SHOW VARIABLES LIKE ‘partition’ 查看是否支持分區。
創建表時使用partition關鍵詞設置分區。
若有主鍵或唯一鍵,則分區關鍵詞必須是其中之一。
分區類型:
- RANGE: 按照取值範圍進行分區。NULL值做最小值處理。
- LIST: 利用數組值包含關係進行分區。NULL值如果被允許則必須在候選項中。
- COLUMNS: 多列般的RANGE AND LIST(RANGE COLUMNS AND LIST COLUMNS關鍵詞)。
- HASH: 常規HASH, 列關鍵詞 % 分區數量確定分區號。當需要增加分區時,已有數據遷移代價太大。LINER HASH, 使用更加複雜的算法進行分區使上述得到優化,但使數據分佈不均勻。二者均只支持整數分區(非整數列需要使用函數轉換)。NULL被視爲0值。
- KEY: 支持除BLOB和TEXT外的所有類型列作爲分區鍵。可不指定分區鍵,默認使用主鍵或唯一索引列(非空纔不會報錯)。支持多分區鍵,同樣也可以使用LINIRE KEY。NULL被視爲0值。
## 子分區(複合分區)
可對每個分區(RANGE AND LIST)進行再分區(HASH AND SET)。
## 分區管理
SQL優化
- SHOW (global | session) STATUS LIKE (Com_% | Innodb_rows% | Connections | Uptime | Slow_queries) 查看命令執行DASHBOARD。
- —log-slow-queries=file_name 記錄慢查詢。
- Using explain or desc to analytic sql.
- select_type: SIMPLE 簡單表,PRIMARY: 外層查詢,UNION: UNION中的第二個或後面的查詢,SUBQUERY: 子查詢的第一個SELECT。
-
type:訪問類型,性能由高到低爲:
- NULL: 無需訪問即可得出答案。
- const/system: 僅一個匹配行,如單表查詢中使用主鍵和唯一鍵進行查詢。
- eq_ref: 多表連接中使用主鍵或唯一鍵進行關鍵。
- ref: 使用非唯一索引或唯一索引的前綴匹配。
- ref_or_null: 查詢條件中包含對NULL的查詢。.
- index_merge: 索引合併優化。
- unique_subquery: in後面是一個查詢主鍵字段的子查詢。
- index_subquery: in後面是一個針對非唯一索引字段的子查詢。
- range: 索引範圍掃描,如對於索引列的大於小於between操作。
- index: 索引全掃描,遍歷整個索引查詢匹配到的行。如查詢一個被索引的列。
- ALL: 全表掃描。
- explain extended and then show warnings to show the actual SQL that has been executed after SQL optimization. EXPLAIN PARTITIONS 可用於查看語句將操作的分區。
- SHOW PROFILE(S):
- SELECT @@have_profiling 查看是否支持profile。
- SELECT @@profiling 查看是否開啓此功能(默認關閉)。
- SET profiling=1 開啓此功能。
- SHOW PROFILES查看歷史SQL及耗時。
-
SHOW PROFILE (ALL | CPU | block io | source/源文件 etc.) ROR QUERY x 查看某個SQL的各階段耗時。
- sending data 狀態表示開始訪問數據行並把結果返回,往往需要大量磁盤IO,故往往是最耗時的。
- INFORMATION_SCHEMA.PROFILING 存有profiling信息。
- trace: 查看優化依據。
- SET OPTIMIZER_TTACE=“enabled=on”, END_MARKER_IN_JSON=on;
- SET OPTIMZER_TRACE_MAX_MEM_SIZE=10000000
- INFORMATION_SCHEMA.OPTIMIZER_TRACE
索引
- B-Tree: 廣泛使用。B代表balanced,其非二叉樹。
- HASH: 僅Memory引擎支持。無法用在範圍查找。
- R-Tree: 空間索引,MyISAM的一個特殊索引類型,主要用於地理空間數據類型。
- Full-text: 全文索引。
前綴索引在Order By和Group By時無法使用。且無法實現覆蓋索引掃描。
Using index: 覆蓋索引掃描。所選擇的字段即爲索引,無需額外訪問。
Using where: 根據索引回表訪問數據。需要額外數據訪問或篩選。
Using index condition: 使用ICP(Index Condition Pushdown)的特徵,某些情況下無需訪問數據後篩選。
無法使用索引:
- LIKE “%xx”。
- 存在數據類型隱式轉換。如last_name=1
- 複合索引不包含最左邊列,即不滿足最左原則。
- MySQL估計使用索引比全表掃描更慢。比如last_name LIKE “T%”。使用trace可查看依據。
- OR左側有索引,右側無索引,涉及的索引則均不會被使用。(反正都要全表掃描,沒必要多一次索引掃描增加IO訪問)
SHOW STATUS LIKE “Handler_read%”: key表一個行被索引值讀的次數,越高越好。rnd_next表數據文件中讀下一行的請求數,越低越好。
定期檢查表: (analyze | check) table payment.
定期優化表: 若刪除了表的一大部分(另可使用alter table payment engine=innodb回收不用的空間),對含有可變長度行(VARCHAR, TEXT, BLOB等)的表進行了很多更改,應使用optimize table payment
常用優化
-
大批量插曲數據
- 文本數據採用load data infile 方式導入。
- SET (UNIQUE_CHECKS | AUTOCOMMIT) =0。
- 優化ORDER BY
Using index: 有序索引順序掃描直接返回有序結果。select if from a order by id;
Using filesort: 對返回的數據進行排序。不是通過索引直接返回排序結果的排序都叫filrsort,即時使用索引列排序依然會出現Using filesort. select * from a order by id; more puzzles...where and order by 使用相同的索引並且order by的順序與索引順序相同且排序均爲升序或降序。
sort_buffer_size: 線程獨佔。
max_length_for_sort_data: 若讀取的字段總大小小於此值,則一次讀取滿足條件的所有行,然後在排序區sort buffer中排序後直接輸出結果,內存消耗較大但效率高。否則僅取出排序字段和指針進行上述操作,若sort buffer不夠,則在臨時表中存儲排序結果。排序後根據指針回表讀取記錄。 -
GROUP BY
- 在其後主動添加ORDER BY NULL可取消其默認的排序行爲,增加效率。
-
嵌套查詢
- 沒有連接查詢快
- OR
-
分頁
- 根據索引查出滿足條件的所有行的某個字段後連表。
-
使用SQL提示
- SELECT SQL_BUFFER_RESULTS FROM table_name: 生成臨時結果集,可釋放鎖慢慢將數據回傳給客戶端。
- use index: 指定希望MySQL去參考的索引。
- ignore index: 忽略某些索引。
- force index:
ORDER BY RAND()實現隨機排序。
WITH ROLLUP與ORDER BY互斥。
BIT_AND(),BIT_OR()聚合函數進行位運算。
第19章 優化數據庫對象
SELECT * FROM table PROCEDURE ANALYSE(): 讓MySQL根據已存在的數據特徵給出優化建議。
數據拆分: 垂直拆分,不常用列單獨存儲。水平拆分,不同時期數據於不同表或分區存儲。
逆規範化: 增加冗餘列。組新表。
維護數據完整性: 定時任務,觸發器。
使用中間表提高統計效率。
第20章 鎖
MyISAM, MEMORY: 表級鎖。開銷小,加鎖快,粒度大。適合以查詢爲主,只有少量按索引條件更新數據的應用,如WEB。
InnoDB: 行級鎖,也支持表級鎖。開銷大,加鎖慢,粒度小。併發度高。適合有大量按索引條件併發進行少量數據更新,同時又有併發查詢需求的應用如在在線事務系統。
DBD: 頁級鎖,也支持表級。介於上二者之間。
表鎖(MyISAM)
SHOW STATUS LIKE ‘table%’查看錶鎖爭用情況。
讀鎖可存在多個,有且只有一個寫鎖,寫鎖與讀鎖不共存。
LOCK TABLE(S) table (as t) WRITE給表加鎖。表使用別名時需要爲不同的別名都加鎖。
UNLOCK TABLES釋放鎖。
在自動加鎖的情況下,MyISAM總是直接獲取SQL所需要的所有鎖,所以MyISAM不會出現死鎖。
系統變量 concurrent_insert:
- 0: 不允許併發插曲
- 1: 如果MyISAM表中間沒有空洞,即沒有刪除行,允許讀鎖存在時另一進程在表尾插入記錄。MySQL的默認值,OPTIMIZE TABLE可整理空間碎片。
- 2: 不管有無空洞均允許表尾插入。
鎖調度機制: 等待隊列中有寫鎖請求頁給予最高優先級而與入列順序無關。這也是MyISAM不適合有大量更新和查詢操作的應用的原因。各類操作優先級可設定。maz_write_lock_count可設定當讀請求超過一定值後降低寫操作的優先級。
InnoDB鎖問題
於MyISAM: 有了事務和行級鎖。
併發事務帶來的問題:
- 更新丟失
- 贓讀
- 不可重複讀: 二次讀時數據被更改或刪除。
- 幻讀: 二次讀時有新的滿足查詢條件的結果。
SELECT @@tx_isolation
事務隔離級別:
- 未提交讀: 讀未提交不讀已損壞。
- 已提交讀: 讀已提交。
- 可重複讀:
- 可序列化
SHOW STATUS LIKE “innodb_row_lock%”查看行鎖爭用情況。
SELECT * FROM information_schema.innodb_locks查看鎖等待情況。
通過InnoDB Monitors觀察鎖衝突情況。(show engine innodb status)
InnoDB加鎖方法
SELECT ... LOCK IN SHARE MODE.
SELECT ... FOR UPDATE.
行鎖情形:
- record lock: 對索引項加鎖
- gap lock: 對記錄之間的間隙加鎖,主要作用於範圍篩選。可解決幻讀問題。對於不存在的記錄,也會使用此鎖,故不存在的記錄也會存在衝突。
- next-key lock: 對記錄及其前後間隙加鎖。
死鎖:
- 如果一個事務先對某行加共享鎖(SSLECT)後又需要更新該行數據(UPDATE等),高併發環境下很可能會造成死鎖。
- InnoDB的行鎖時通過給索引上的索引項加鎖實現的,如果沒有索引,將通過隱藏的聚簇索引來對記錄加鎖。如果不通過索引條件檢索數據,InnoDB將對所有記錄加鎖(表鎖)。
- InnoDB是針對索引項加鎖,故如果使用同一索引鍵操作不同行的記錄,也會出現行衝突。
- 通過不同索引鍵獲取同一記錄的鎖也會衝突。
- 是否使用索引是MySQL通過計算不同執行計劃的代價決定的,所以分析鎖衝突時,有時需要檢查SQL的執行計劃。
BINLOG, 執行Log.
set innodb_locks_unsafe_for_binlog=‘on’: 在UPDATE INTO target ... SELECT ...source和CREATE TABLE target ... SELECT ... source時不給source加鎖。這會造成併發更新source相關字段時(不會被阻塞),binlog中日誌順序出現錯誤,數據恢復和複製會出現主從不一致的情況。這些SQL稱爲不確定的SQL(unsafe SQL)。默認爲off,但對於複雜查詢可能會有嚴重的性能問題,故可以使用導出文件再加載文件的方式。
複製模式
SET SESSION ISOLATION LEVEL SERIALIZABLE: 動態改變隔離級別。