MySQL-01-日常運維

範式和反範式
  1. 範式和反範式是庫表設計過程中的概念
  2. 目前關係數據庫有六種範式,越高的範式數據庫冗餘越小
  3. 範式化可以較少冗餘,從而減少了在更新數據時一致性方面的開銷
  4. 反範式化由於冗餘的數據,在複雜的查詢場景下,可以避免聯合查詢和子查詢,提高查詢的效率
  5. 根據業務場景,選擇合適的範式等級進行庫表設計,是日常運維中的第一步
查詢優化
  1. 使用索引
    • 索引的使用,遵循最左前綴原則
    • 使用覆蓋索引,可以減少反表操作,大大提高效率,order/group by 也可以使用覆蓋索引
    • varchar 等字符串類型,可以使用前綴索引提高查詢效率
    • like 匹配也遵循最左前綴原則,例如 ‘aaa%’ 格式才能使用索引
    • NULL 類型對索引不友好,字段默認應該設置爲 NOT NULL
    • where 字句裏面,如果字段標識符使用了函數運算,會導致該字段無法使用索引
    • 避免冗餘和重複索引
  2. 多表查詢的類型
    • 子查詢(exist/in)
    • 內連接(inner join)
    • 外連接(left/right/full join)
  3. 多表查詢中的驅動表和被驅動表
情況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 表
  1. 多表查詢的優化原則
    • 情況 3 中子查詢是用不到索引的,優化方式是改爲情況 1 的寫法,利用聯合查詢提高效率
    • 小表驅動大表,指的是驅動表要儘量走索引,使結果集儘量小,上面三種情況中要求 t1.type 必須有索引,並且過濾度要高
    • 連接字段索引,被驅動表上的關聯字段必須有索引,上面三種情況中要求 t2.name 必須有索引
  2. 可以使用 show profile 查看查詢執行時在每個階段的開銷
  3. 可以使用 explain 查看查詢的執行路徑
  4. 可以使用 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,記錄數據的變化
變更守則
  1. 有驗證方案,分批次,灰度發佈
  2. 發佈過程有日誌,可監控
  3. 有回滾方案
  4. 選擇業務低峯期發佈
其他
  • 操作數據時,各個環節的字符集最好保持一致,否則容易出現亂碼
    • 數據庫訪問時 SESSION 的字符集character_set_client/character_set_connection
    • MySQL SERVER 默認字符集character_set_server
    • 數據庫的默認字符集create database db_name character set utf8mb4;
    • 數據表的默認字符集
    • 操作系統字符集
    • SSH 客戶端字符集
    • mysqldump 時使用 binary 類型或者 utf8mb4 類型,可以兼容所有字符集
  • 操作系統時間和數據庫默認時區最好保持一致,否則now()函數容易發生問題
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章