範式和反範式
範式和反範式是庫表設計過程中的概念
目前關係數據庫有六種範式,越高的範式數據庫冗餘越小
範式化可以較少冗餘,從而減少了在更新數據時一致性方面的開銷
反範式化由於冗餘的數據,在複雜的查詢場景下,可以避免聯合查詢和子查詢,提高查詢的效率
根據業務場景,選擇合適的範式等級進行庫表設計,是日常運維中的第一步
查詢優化
使用索引
索引的使用,遵循最左前綴原則
使用覆蓋索引,可以減少反表操作,大大提高效率,order/group by 也可以使用覆蓋索引
varchar 等字符串類型,可以使用前綴索引提高查詢效率
like 匹配也遵循最左前綴原則,例如 ‘aaa%’ 格式才能使用索引
NULL 類型對索引不友好,字段默認應該設置爲 NOT NULL
where 字句裏面,如果字段標識符使用了函數運算,會導致該字段無法使用索引
避免冗餘和重複索引
多表查詢的類型
子查詢(exist/in)
內連接(inner join)
外連接(left/right/full join)
多表查詢中的驅動表和被驅動表
情況1: select * from (select id,name from t1 where t1.type=3) as t3, t2 where t2.name = t3.name and t2.age>20;
情況2: select * t1 left join t2 on t1.name=t2.name where t2.age>20 and t1.type=3;
情況3: select * from t1 where t1.tape=3 and t1.name in (select t2.name from t2 where t2.age>20)
上述三種情況中,t1 是驅動表,t2 是被驅動表,查詢的步驟是:
1. 根據篩選條件,獲取 t1 表相關的結果集
2. 使用 t1 中的關聯字段,去遍歷 t2 表
多表查詢的優化原則
情況 3 中子查詢是用不到索引的,優化方式是改爲情況 1 的寫法,利用聯合查詢提高效率
小表驅動大表,指的是驅動表要儘量走索引,使結果集儘量小,上面三種情況中要求 t1.type 必須有索引,並且過濾度要高
連接字段索引,被驅動表上的關聯字段必須有索引,上面三種情況中要求 t2.name 必須有索引
可以使用 show profile
查看查詢執行時在每個階段的開銷
可以使用 explain
查看查詢的執行路徑
可以使用 hint
強制使用某個索引或者不適用索引
其他優化
delete 清理過期數據一定要使用 limit 分片,否則可能導致
鎖住很多數據
佔滿整個事務日誌
耗盡系統資源
阻塞重要查詢
-DELETE FROM messages WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH) LIMIT 10000;
使用 truncate 清理所有數據的操作可以用下列操作代替,從而做到“灰度”、“可回滾”
create table_name_tmp like table_name;
rename table_name to test.dbname_tablename_time;
rename table_name_tmp to table_name;
online ddl, 不鎖表的 dd
通過新建一個鏡像表,在新表上做 ddl
做 ddl 過程中使用觸發器複製數據
最後後,在業務低峯期,使用rename
替換掉原來的表
核心思想是,空間換取時間
optimize table 優化表空間
delete 數據並不會釋放表空間
某些表經過長時間的積累,會導致大量的空間浪費
運行狀態
查看當前工作線程 show [full] processlist;
全局狀態查詢 show status;
,常用的參考狀態如下:
Aborted_clients 由於客戶沒有正確關閉連接已經死掉,已經放棄的連接數量。
Aborted_connects 嘗試已經失敗的MySQL服務器的連接的次數。
Connections 試圖連接MySQL服務器的次數。
Created_tmp_tables 當執行語句時,已經被創造了的隱含臨時表的數量。
Delayed_insert_threads 正在使用的延遲插入處理器線程的數量。
Delayed_writes 用INSERT DELAYED寫入的行數。
Delayed_errors 用INSERT DELAYED寫入的發生某些錯誤(可能重複鍵值)的行數。
Flush_commands 執行FLUSH命令的次數。
Handler_delete 請求從一張表中刪除行的次數。
Handler_read_first 請求讀入表中第一行的次數。
Handler_read_key 請求數字基於鍵讀行。
Handler_read_next 請求讀入基於一個鍵的一行的次數。
Handler_read_rnd 請求讀入基於一個固定位置的一行的次數。
Handler_update 請求更新表中一行的次數。
Handler_write 請求向表中插入一行的次數。
Key_blocks_used 用於關鍵字緩存的塊的數量。
Key_read_requests 請求從緩存讀入一個鍵值的次數。
Key_reads 從磁盤物理讀入一個鍵值的次數。
Key_write_requests 請求將一個關鍵字塊寫入緩存次數。
Key_writes 將一個鍵值塊物理寫入磁盤的次數。
Max_used_connections 同時使用的連接的最大數目。
Not_flushed_key_blocks 在鍵緩存中已經改變但是還沒被清空到磁盤上的鍵塊。
Not_flushed_delayed_rows 在INSERT DELAY隊列中等待寫入的行的數量。
Open_tables 打開表的數量。
Open_files 打開文件的數量。
Open_streams 打開流的數量(主要用於日誌記載)
Opened_tables 已經打開的表的數量。
Questions 發往服務器的查詢的數量。
Slow_queries 要花超過long_query_time時間的查詢數量。
Threads_connected 當前打開的連接的數量。
Threads_running 不在睡眠的線程數量。
Uptime 服務器工作了多少秒。
終止某個線程 kill thread_id;
,使用場景有
終止死鎖事務
終止慢 SQL
終止長事務導致的長時間鎖表
常用日誌
錯誤日誌,對應參數log_error
,錯誤日誌記錄着mysqld啓動和停止,以及服務器在運行過程中發生的錯誤的相關信息。
慢查詢日誌,相關參數log_slow_queries
,記錄查詢時間大於 long_query_time
設定時間的查詢
普通查詢日誌,對應參數log_output
,記錄所有查詢語句
二進制日誌(binlog),相關參數sync_binlog
,記錄數據的變化
變更守則
有驗證方案,分批次,灰度發佈
發佈過程有日誌,可監控
有回滾方案
選擇業務低峯期發佈
其他
操作數據時,各個環節的字符集最好保持一致,否則容易出現亂碼
數據庫訪問時 SESSION 的字符集character_set_client/character_set_connection
MySQL SERVER 默認字符集character_set_server
數據庫的默認字符集create database db_name character set utf8mb4;
數據表的默認字符集
操作系統字符集
SSH 客戶端字符集
mysqldump 時使用 binary 類型或者 utf8mb4 類型,可以兼容所有字符集
操作系統時間和數據庫默認時區最好保持一致,否則now()
函數容易發生問題