1. 程式人生 > >校招面試中常見的 MySQL 考察難點和熱點

校招面試中常見的 MySQL 考察難點和熱點

基本架構

MySQL是典型的三層架構模式,在平常使用中對MySQL問題排查和優化,也應該針對具體問題,從對應的層解決問題

  • 服務層:經典的C/S架構,主要是處理連線和安全驗證。
  • 核心層:處理MySQL核心業務。
  • 查詢分析,優化,快取和內建函式 。
  • 內建的檢視,儲存過程,觸發器。
  • 儲存引擎層:儲存引擎負責資料的儲存和提取。核心層通過儲存引擎的 API 與儲存引擎通訊,來遮蔽不同儲存引擎的差異 , 使得差異對上層透明化。

MySQL調優必備18個引數

連線數 、會話數和執行緒數

  • max_connections

    max_connections引數用來設定最大連線 ( 使用者 ) 數 。每個連線MySQL的使用者均算作一個連線,

    max_connections的預設值為100 。

    MySQL無論如何都會為管理員保留一個用於登入的連線,因此實際MySQL最大可連線數為

    max_connections+1。

    max_connections 最大為16384 。

    該引數設定過小的話,會出現”Too many connections”錯誤。

    檢視max_connections引數的方法:

mysql> show variables like "max_connections"; 

修改最大可連線數的方法有:

# 方法一:即時生效,無需重啟MySQL,重啟失效
1.root登入MySQL:
$ mysql -uroot -p
2.檢視當前的Max_connections引數值:
mysql> SELECT @@MAX_CONNECTIONS AS 'Max Connections'
; 3.設定該引數的值: mysql> set global max_connections = 200; # 方法二:需要重啟MySQL,重啟不失效,修改my.conf max_connections=200 # 方法三:編譯MySQL的時候,設定預設最大連線數 1.開啟MySQL原始碼,進入SQL目錄,修改mysqld.cc檔案: {"max_connections", OPT_MAX_CONNECTIONS, "The number of simultaneous clients allowed.", (gptr*) &max_connections, (gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 100, 1, 16384, 0, 1, 0}, 2. 編譯三部曲 $ ./configure $ make $ make install
  • maxconnecterrors

    maxconnecterrors是一個MySQL中與安全有關的計數器值,它負責阻止過多嘗試失敗的客戶端以防止暴力破解密碼的情況。maxconnecterrors的值與效能並無太大關係。

由於出現某臺host連線錯誤次數等於maxconnecterrors , 日誌中會出現類似blocked because of many connection errors 的資訊,解決方法如下:

1.執行mysqladmin flush-hosts或者重啟 MySQL服務,將錯誤計數器清零
2.my.cnf修改max_connect_errors的值,可以適當大些
  • thread_concurrency

是在特定場合下才能使用的,這個變數是針對Solaris系統的,如果設定這個變數的話,mysqld就會呼叫thr_setconcurrency().這個函式使應用程式給同一時間執行的執行緒系統提供期望的執行緒數目。

CPU核數的2倍,比如有一個雙核的CPU,那麼thread_concurrency的應該為4;2個雙核的cpu, thread_concurrency的值應為8。

資料包和快取

  • maxallowedpacket

    這個引數是限制server允許通訊的最大資料包大小,有時候可能因為這個引數設定過小,比較大的insert或者update操作會失敗,所以引數應該設定大一些

  • keybuffersize

    關鍵詞緩衝區大小,快取MyISAM索引塊 ,決定索引處理速度,讀取索引處理。

根據增大Key_reads / Uptime 來優化這個引數檢視Key_reads / Uptime 的方法:

$ mysqladmin ext -ri10 | grep Key_reads
  • threadcachesize

    此引數用來快取空閒的執行緒,以至不被銷燬,如果執行緒快取中有空閒執行緒,這時候如果建立新連線,MYSQL就會很快的響應連線請求。

使用 show status檢視當前mysql連線情況 :

mysql>SHOW STATUS WHERE Variable_name LIKE '%Thread%';

Threads_cached:代表當前此時此刻執行緒快取中有多少空閒執行緒。
Threads_connected:代表當前已建立連線的數量,因為一個連線就需要一個執行緒,所以也可以看成當前被使用的執行緒數。
Threads_created:代表從最近一次服務啟動,已建立執行緒的數量。
Threads_running:代表當前啟用的(非睡眠狀態)執行緒數。並不是代表正在使用的執行緒數,有時候連線已建立,但是連線處於sleep狀態,這裡相對應的執行緒也是sleep狀態。

建議threadcachesize設定成與threads_connected一樣 。

  • sortbuffersize

    每個連線需要使用 buffer 時分配的記憶體大小,不是越大越好。例 : 1000個連線 , 一個1MB,會佔用1GB記憶體,200WX1MB=20GB

  • joinbuffersize

    為了減少參與 join 的 ” 被驅動表 “的讀取次數以提高效能 , 需要使用到join buffer來協助完成 join 操作當 join buffer 太小,MySQL 不會將該buffer存入磁碟檔案而是先將join buffer中的結果與需求join的表進行操作,然後清空 join buffer 中的資料,繼續將剩餘的結果集寫入次buffer中,如此往復,這勢必會造成被驅動表需要被多次讀取,成倍增加IO訪問,降低效率 。

  • querycachesize

    查詢快取大小,再查詢時返回快取,快取期間表必須沒有被更改,否則快取失效,多寫入操作的話設定大了會影響寫入效率。

mySQL用於查詢的快取的記憶體被分成一個個變長資料塊,用來儲存型別,大小,資料等資訊。 當伺服器啟動的時候,會初始化快取需要的記憶體,是一個完整的空閒塊。當查詢結果需要快取的時候,先從空閒塊中申請一個數據塊大於引數querycacheminresunit的配置,即使快取資料很小,申請資料塊也是這個,因為查詢開始返回結果的時候就分配空間,此時無法預知結果多大。

配記憶體塊需要先鎖住空間塊,所以操作很慢,MySQL會盡量避免這個操作,選擇儘可能小的記憶體塊,如果不夠,繼續申請,如果儲存完時有空餘則釋放多餘的。 快取存放在一個引用表中,通過一個雜湊值引用,這個雜湊值包括查詢本身,資料庫,客戶端協議的版本等,任何字元上的不同,例如空格,註釋都會導致快取不命中。

當查詢中有一些不確定的資料時,是不會快取的,比方說now(),current_date(),自定義函式,儲存函式,使用者變數,字查詢等。所以這樣的查詢也就不會命中快取,但是還會去檢測快取的,因為查詢快取在解析SQL之前,所以MySQL並不知道查詢中是否包含該類函式,只是不快取,自然不會命中。 快取存放在一個引用表中,通過一個雜湊值引用,這個雜湊值包括查詢本身,資料庫,客戶端協議的版本等,任何字元上的不同,例如空格,註釋都會導致快取不命中。

  • readbuffersize

    這個引數是MySQL讀入緩衝區的大小,將對錶進行順序掃描的請求將分配一個讀入緩衝區,mysql會為它分配一段記憶體緩衝區,readbuffersize變數控制這一緩衝區的大小,如果對錶的順序掃描非常頻繁,並你認為頻繁掃描進行的太慢,可以通過增加該變數值以及記憶體緩衝區大小提高其效能,read_buffer_size變數控制這一提高表的順序掃描的效率 資料檔案順序。

  • readrndbuffer_size

    這個引數是MySQL的隨機讀緩衝區大小,當按任意順序讀取行時(列如按照排序順序)將分配一個隨機讀取緩衝區,進行排序查詢時,MySQL會首先掃描一遍該緩衝,以避免磁碟搜尋,提高查詢速度,如果需要大量資料可適當的調整該值,但MySQL會為每個客戶連線分配該緩衝區所以儘量適當設定該值,以免記憶體開銷過大。表的隨機的順序緩衝 提高讀取的效率。從排序好的資料中讀取行時,行資料從緩衝區讀取的大小,會提升order by效能 注意:MySQL會為每個客戶端申請這個緩衝區,併發過大時,設定過大影響記憶體開銷。

  • myisamsortbuffer_size

    MyISAM表發生變化時,重新排序所需的快取。

  • innodbbufferpool_size

    InnoDB 使用快取儲存索引,儲存原始資料的快取大小,可以有效減少讀取資料所需的磁碟IO。

日誌和事務

  • innodblogfile_size

    資料日誌檔案大小,大的值可以提高效能,但增加了恢復故障資料庫的時間(恢復故障資料庫時需要讀取資料日誌檔案,當日志過大會導致時間過長)。

  • innodblogbuffer_size

    日誌檔案快取,增大該檔案可以提高效能,但增大了忽然宕機後損失資料的風險(日誌檔案在快取中,還沒來得及存進硬碟就斷電了)。

  • innodbflushlogattrx_commit

    執行事務的時候,會往InnoDB儲存引擎的日誌快取插入事務日誌,寫資料前先寫日誌(預寫日誌方式)設定為0,實時寫入;當設定為1時,快取實時寫入磁碟;2時,快取實時寫入檔案,每秒檔案實時寫入磁碟。

  • innodblockwait_timeout

    回滾前(當一個事務被撤銷時),一個InnoDB事務,應該等待一個鎖被批准多久,當InnoDB無法檢測死鎖時,這個值就有用了。

軟體優化

1. 選擇合適的引擎

MyISAM 索引順序訪問方法,支援全文索引,非事務安全,不支援外來鍵,會加表級鎖存在三個檔案:

  • FRM 存放表結構
  • MYD 存放資料
  • MYI 存放索引

InnoDB 事務型儲存引擎,加行鎖,支援回滾,崩潰恢復,ACID事務控制,表和索引放在一個表空間裡頭,表空間多個檔案。

例:
    update tableset age=3 where name like "%jeff%";
    //會鎖表

2. 正確使用索引

給合適的列表建立索引,給where子句,連線子句建立索引,而不是select選擇列表索引值應該不相同,唯一值時效果最好,大量重複效果很差使用短索引,指定字首長度char(50)的前20,30值唯一例。檔名索引快取一定(小)時,存的索引多,消耗IO更小,能提高查詢速度最左字首n列索引,最左列的值匹配,更快。

like查詢,索引會失效,儘量少用like。百萬、千萬資料時,用like Sphinx開源方案結合MySQL不能濫用索引。

  • 索引佔用空間。
  • 更新資料,索引必須更新,時間長,儘量不要用在長期不用的欄位上建立索引。
  • SQL執行一個查詢語句,增加查詢優化的時間。

3. 避免使用SELECT

  • 返回結果過多,降低查詢的速度。
  • 過多的返回結果,會增大伺服器返回給APP端的資料傳輸量。例:網路傳輸速度面,弱網路環境下,容易造成請求失效。

4. 欄位儘量設定為NOT NULL

“” 和 NULL問題

{“name”:”myf”} {“name”:””} {“hobby”:空array}

NULL佔空間

例:安卓需要判斷””還是NULL

Java和OC都是強型別,會造成APP閃退

硬體優化

1. Linux核心用記憶體開快取存放資料

寫檔案:檔案延遲寫入機制,先把檔案存放到快取,達到一定程度寫進硬碟。

讀檔案:同時讀檔案到快取,下次需要相同檔案直接從快取中取,而不是從硬碟取。

2. 增加應用快取

本地快取:資料防盜伺服器記憶體的檔案中。

分散式快取:Redis, Mencache 讀寫效能非常高,QPS(每秒查詢請求數)每秒達到1W以上;資料持久化用Redis,不持久化兩者都可以。

3. 用SSD代替機械硬碟

日誌和資料分開儲存,日誌順序讀寫 – 機械硬碟,資料隨機讀寫 – SSD

可以調引數

#作業系統禁用快取,直接通過fsync方式將資料刷入機械硬碟
innodb_flush_method = O_DIRECT

# 控制MySQL中一次重新整理髒頁的數量,SSD io 增強,增大一次輸入髒頁的數量
innodb_in_capacity = 1000

4. SSD+SATA混合儲存,FlashCache: Facebook開源在檔案系統和裝置驅動之間加了一層快取,對熱資料快取

架構優化

1. 分表

水平拆分:資料分成多個表拆分後的每張表的表頭相同。

垂直拆分:欄位分成多個表。

插入資料、更新資料、刪除資料、查詢資料時:MyISAM MERGE儲存引擎,多個表合成一個表,InnoDB用alter table,變成MyISAM儲存引擎,然後MEGRE。

面試題:MERGE儲存引擎將N個表合併,資料庫中如何儲存?答: 真實儲存為N個表,表更大的話就需要分庫了。

2. 讀寫分離

讀是一些機器,寫是一些機器,二進位制檔案的主從複製,延遲解決方案。資料庫壓力大了,可以把讀和寫拆開,對應主從伺服器,主伺服器寫操作、從伺服器是讀操作。大多數業務是讀業務。京東、淘寶大量瀏覽商品、挑選商品是讀操作(多),購買是寫操作(少)。主伺服器寫操作的同時,同步到從伺服器,保持資料完整性——主從複製。

主從複製原理:基於主伺服器的二進位制日誌(binlog)跟蹤所有的對資料庫的完整更改實現要實現主從複製,必須在主伺服器上啟動二進位制日誌主從複製是非同步複製。

三個執行緒參與:主伺服器一個執行緒(IO執行緒)、從伺服器兩個(IO執行緒和SQL執行緒)

主從複製過程:

  • 從資料庫,執行start slave開啟主從複製。
  • 從資料庫IO執行緒會通過主資料庫授權的使用者請求連線主資料庫,並請求主資料庫的binlog日誌的指定位置,change master命令指定日誌檔案位置。
  • 主資料庫收到IO請求,負責複製的IO執行緒跟據請求讀取的指定binlog檔案返回給從資料庫的IO執行緒,返回的資訊除了日誌檔案,還有本次返回的日誌內容在binlog檔名稱和位置。
  • 從資料庫獲取的內容和位置(binlog),寫入到(從資料庫)relaylog中繼日誌的最末端,並將新的binlog檔名和位置記錄到master-info檔案,方便下次讀取主資料庫的binlog日誌,指定位置,方便定位。
  • 從資料庫SQL執行緒,實時檢測本地relaylog新增內容,解析為SQL語句,執行。

弊端:延遲

主從複製延遲解決方案:

  • 定位問題:延遲瓶頸,IO壓力大,升級硬體,換成SSD
  • 單執行緒從relaylog執行MySQL語句延遲,換成MySQL5.6以上版本多執行緒,或者Tungsten第三方並行複製工具
  • 都不行,直接分庫

3. 分庫

Cobar方案:阿里開源(後續無更新)

MyCat基於Cobar,MySQL通訊協議,代理伺服器,無狀態,容易部署,負載均衡。

原理:應用伺服器傳SQL語句,路由解析,轉發到不同的後臺資料庫,結果彙總,返回MyCat把邏輯資料庫和資料表對應到物理真實的資料庫、資料表,遮蔽了物理差異性。

MyCat工作流程:

  • 應用伺服器向MyCat傳送SQL語句select * from user where id in(30, 31, 32)。
  • MyCat前端通訊模組與應用伺服器通訊,交給SQL解析模組。
  • SQL解析模組解析完交給SQL路由模組。
  • SQL路由模組,id取模,餘數為0:db1,餘數為1:db2……
  • 把SQL拆解為select * from user where id in 30……交給SQL執行模組,對應db1 db2 db3。
  • SQL執行模組通過後端,分別在db1 db2 db3執行語句,返回結構到資料集合合併模組,然後返回給應用伺服器。

SQL慢查詢分析、調引數

慢查詢:指執行超過一定時間的SQL查詢語句記錄到慢查詢日誌,方便開發人員檢視日誌

找問題:

long_qeury_time定義慢查詢時間
slow_query_log設定慢查詢開關
slow_query_log_file設定慢查詢日誌檔案路徑

設定方法1:

set log_query_time = 1;
set slow_query_log = on;
set slow_query_log_file = '/data/slow.log'

設定方法2:

/etc/my.comf設定引數

分析:

explain命令進行分析,輸出結構含義,官方文件。

作者介紹:

@止齋少主
熱愛程式設計技術多年,原河北Linux使用者組負責人之一,熱愛組織開源技術活動,在校期間主攻機器學習和資訊保安技術,專案經驗豐富參與中電54所SIP尋呼產品後臺研發、車聯網APP後臺開發與架構設計,自主創業研發公式搜尋引擎並申請國家發明專利一項。校招中先後拿到多家公司offer後臺開發或機器學習演算法offer。在百度參與資訊流廣告專案研發、內容生態系統建設、中間頁廣告演算法策略研發、廣告系統檢索端開發,現在在某創業公司做機器學習和資料探勘方向。