1. 程式人生 > 其它 >c++的for迴圈訓練(三)

c++的for迴圈訓練(三)

目錄

mysql官方文件 https://dev.mysql.com/doc/refman/

一條查詢語句的執行流程

1. 連線

Mysql服務監聽的埠預設為3306,有專門負責處理連線的模組,連線是需要許可權驗證。

如何檢視mysql的連線數?

  show global status 'Thread%';

欄位 含義
Threads_cached 快取中的執行緒連線數
Threads_connected 當前開啟的連線數
Threads_created 為處理連線建立的執行緒數
Threads_running 非睡眠狀態的連線數,通常指併發連線數

為何檢視mysl的連線數是“show Thread”檢視執行緒數呢?

因為客戶端每產生一個連線或一個會話,在伺服器端就會建立一個執行緒來處理。反過來,如果要結束會話,就需要殺死程序。

每一個連線都分配執行緒的話,毋庸置疑是需要消耗服務端資源的,所以在連線時長連線數(併發量)上mysql就做了些處理。

  1. 連線時長:mysql會把長時間不活動(sleep)的連線自動斷開。
   show variables like 'wait_timeout';  --非互動式超時時間,如JDBC程式

   show variables like 'max_connections';   --互動式超時時間,如資料庫工具

互動式和非互動式的預設連線超時時長都是28800秒(8小時)。

  1. 連線數:mysql服務允許最大的連線數(併發數)是多少?
  show variables like 'max_connections';

下圖中的最大連線數為200(這裡是我自己做了修改),在mysql5.7和目前的mysql8.0的版本中,mysql的預設最大連線數為151,最大可支援設定成100000(10w)

mysql8.0官網關於max_connections的描述

2. 查詢快取

mysql中查詢快取預設為關閉狀態(不推薦使用),且mysql8.0中已經將查詢快取移除了。需要快取還是交給ORM(如:mybatis預設開啟一級快取)框架或redis等第三方服務來實現。

 show variables like 'query_cache%';

3. 語法解析和預處理

主要是對sql語句基於SQL語法進行詞法分析語法分析以及語義解析

3.1 詞法分析:就是把一條sql語句分成一個個單詞。

select * from student where student = '1';

會分成select、*、from、student、where、student、=、'1'八個單詞,每個單詞從哪開始從哪結束,是什麼型別。

3.2 語法分析
及對SQL做一些語法檢查,比如單引號是否閉合、識別關鍵字等,然後根據SQL語法規則,生成解析樹(select_lex)。

3.3 前處理器
在語法分析的基礎上(解決語法分析無法解析的語義),對錶名、列名是否存在、別名是否異常等問題進行解析處理,進一步生成一個新的解析樹。

4.查詢優化和查詢執行計劃

4.1 查詢優化器
查詢優化器的目的就是根據解析樹生成不同的執行計劃(Execution Plan),然後選擇一種最優的執行計劃,MySQL裡面使用的是基於開銷(cost)的優化器,哪種計劃開銷最小,就用哪種。
檢視查詢的開銷:

show status like 'Last_query_cost';

4.2 優化器都做哪些優化?
如:
兩表關聯查詢時,以哪個表為基準表;
多個索引可以使用時,使用哪個索引等等。

以下來自《資料庫查詢優化器藝術-原理解析與SQL效能優化》
4.2.1 子查詢優化
4.2.2 等價謂詞重寫
4.2.3 條件簡化
4.2.4 外連線消除
4.2.5 巢狀連線消除
4.2.6 連線的消除
4.2.7 語義優化
4.2.8 非SPJ優化

優化完之後,優化器會把解析樹變成一個查詢執行計劃,查詢執行計劃是一個數據結構。
可以通過在sql語句前加上explain來檢視執行計劃的資訊
如:

EXPLAIN select name from student where id = 1;

獲取詳細資訊:

EXPLAIN FORMAT=JSON select name from student where id = 1;

5.儲存引擎

mysql支援多種儲存引擎,常用的有MyISAM和InnoDB,5.5.5之前mysql預設的儲存引擎為MyISAM,5.5.5之後mysql預設的儲存引擎為InnoDB。

常見的儲存引擎
5.7 https://dev.mysql.com/doc/refman/5.7/en/storage-engines.html
8.0 https://dev.mysql.com/doc/refman/8.0/en/storage-engines.html

MyISAM

  • 通常用於只讀或以讀為主的工作,表級鎖定限制了讀寫效能。
    特點:
  • 支援表級別的鎖(插入和更新會鎖表)。不支援事物。
  • 擁有較高的插入(insert)和查詢(select)速度。
  • 儲存了表的行數(count速度更快)。

tips: 怎麼快速向資料庫插入100w條資料?

  • 可以先用MyISAM插入資料,然後修改儲存引擎為InnoDB。

InnoDB

5.7、8.0版本中預設的儲存引擎,適合經常更新的表,存在併發讀寫或者有事務處理的業務系統

  • 支援事務,支援外來鍵,因此資料的完整性,一致性更高
  • 支援行級別的鎖和表級別的鎖
  • 支援讀寫併發,寫不阻塞讀(MVCC)。啥是MVCC?以後再說。
  • 特殊的索引存放方式,可以減少IO,提升查詢效率

一條更新語句是如何執行的

執行流程簡述

一個簡化後的過程(因為更新操作涉及到事務,這裡先記一個大概的流程示例)

要將student表中id=1的學生姓名(原為lisi)修改為zhangsan,執行sql語句

update student set name='zhangsan' where id=1;

  1. 事務開始,從記憶體(buffer pool)或磁碟取到包含這條資料的資料頁,返回給Server的執行器;
  2. 執行器修改資料頁的一行資料;
  3. 記錄修改之前的內容到undo log,如update student set name='lisi' where id=1;;
  4. 記錄要修改的操作到redo log,如update student set name='zhangsan' where id=1;
  5. 呼叫儲存引擎介面,記錄資料頁到buffer pool
  6. 事務提交。

緩衝池 Buffer Pool

InnoDB設定了一個儲存引擎從磁碟讀取資料到記憶體的最小單位,叫做

作業系統也有頁的概念。作業系統的頁大小一般是4k(傳聞中的4k對齊),在InnoDB中,這個最小的單位預設是16KB大小。若需要修改這個值的話,修改後需要清空資料重新初始化服務。

https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_page_size

也就是說InnoDB儲存引擎從磁碟讀取資料的時候,每次最少讀16KB的資料,我們所需要的操作的資料就在這樣的頁裡面,也就是常常說的資料頁。

而我們每次拿資料如果都從磁碟中取出來放入記憶體的話,還是避免不了頻繁io消耗資源的問題,這裡就還是需要一個快取的思想,把讀取過的資料頁快取起來。

InnoDB設計了一個記憶體的緩衝區。讀取資料的是會,先判斷緩衝區內是否存在,若存在則直接取用,不存在則從磁碟讀取後將資料放入這個記憶體的緩衝區內。這個緩衝區就叫做Buffer Pool

修改資料時,也是先寫到buffer pool,而不是直接寫到磁碟。記憶體的資料頁和磁碟資料不一致的時候,我們把記憶體取的這部分資料叫做髒頁。InnoDB中有專門的後臺執行緒把buffer pool的資料寫到磁碟,每隔一段時間就會一次性的把多個修改寫入(同步)的磁碟,這個動作就叫做刷髒

有次可見,Buffer Pool的作用就是為了提高讀寫的效率。

redo log

因為刷髒不是實時的,如果Buffer Pool裡面的髒頁沒有同步到磁碟時,伺服器或者資料庫宕機或者重啟,這些資料就會丟失。如何避免這部分資料的丟失,實現記憶體內資料的持久化呢?

InnoDB把所有對“頁”的修改操作寫入到一個操作日誌檔案中。如果髒頁中的內容沒有同步到磁碟時,資料庫再啟動的時候,會從這個日誌檔案進行恢復操作(實現crash-safe)。我們說的事務的ACID中的D(永續性),就是用它來實現的。

這個日誌檔案就叫做redo log(重做日誌)。

  • 既然都要寫磁碟,為何不直接寫到DBFile裡面,還要先寫日誌再寫磁碟呢?

    • 這個與順序io和隨機io有關
    • 如果需要的資料是隨機分散在磁碟的不同頁的不同扇區中的,那麼找到相應的資料需要等磁臂旋轉到指定的頁,然後碟片尋找到對應的扇區(定址的過程),才能找到所需要的的一塊資料,依次進行此過程(不斷地重新定址)直到找完所有資料,這個就是隨機IO。
    • 順序IO是指讀寫操作的訪問地址連續。如碟片已經找到了第一塊資料所在的扇區(定址成功)後,並且其他所需的資料就在這一塊資料後邊,那麼就不需要重新定址,可以依次拿到所需的資料,這個就叫順序IO。
    • 直接寫資料檔案(寫資料(寫聚簇索引)、寫索引(普通索引))是隨機I/O,而記錄日誌是順序I/O(不斷地追加),因此先把修改寫入日誌檔案,在保證了記憶體資料安全性的情況下,可以延遲刷盤時機,進而提升系統吞吐量。

  • redo log特點

    • 為InnoDB提供了崩潰恢復的特性,實現永續性
    • redo log的大小是固定的,前面的內容會被覆蓋,一旦寫滿,就會觸發buffer pool到磁碟的同步,以便騰出空間記錄後面的修改。
    • 預設有兩個檔案ib_logfile0和ib_logfile1,每個48m。

可以通過以下命令檢視InnoDB中redo log的相關引數:

show variables like 'innodb_log%';

引數 含義
innodb_log_size 每個檔案的大小,預設48M
innodb_log_files_in_group 檔案的數量,預設為2個
innodb_log_group_home_dir 檔案所在路徑,如果不指定,則為datadir的路徑

除了redo log外,還有一個跟修改相關的日誌,叫做undo log。redo log和undo log與實務密切相關,統稱為事務日誌。

undo log

undo log(撤銷日誌或回滾日誌)記錄了實務發生之前的資料狀態,分為insert undo log和update updo log。如果修改資料時出現異常,可以用undo log來實現回滾操作(保持原子性)。

show variables like '%undo%';

引數 含義
innodb_undo_directory uodo檔案的路徑
innodb_undo_log_truncate 是否開啟線上回收undo log日誌檔案
innodb_max_undo_log_size undo檔案的大小。如果開啟了innodb_undo_log_truncate,超過這個大小的時候就會觸發truncate回收動作,如果page大小是16kb,truncate後空間縮小到10M。預設1073741824位元組=1G。
innoidb_undo_tablespaces 設定undo獨立表空間個數,範圍為0-95,預設為0。0表示不開啟獨立undo表空間,且undo日誌儲存在ibdata檔案中。
innodb_undo_log_encrypt