天天看點

mysql 原理及配置優化

假設我們用文本存儲的資料和資料庫裡一樣的資料結構并且遵循三範式,那資料庫相比文本存儲有什麼大的優勢呢。

有了這個疑問後我們來簡單探究下mysql資料庫的原理,簡單了解原理後我們在學習下配置的簡單優化。

我們先看下mysql的結構圖

mysql 原理及配置優化

1.最上層是一些用戶端和連接配接服務,包含本地sock通信和大多數基于用戶端/服務端工具實作的類似于tcp/ip的通信。主要完成一些類似于連接配接處理、授權認證、及相關的安全方案。在該層上引入了線程池的概念,為通過認證安全接入的用戶端提供線程。同樣在該層上可以實作基于SSL的安全連結。伺服器也會為安全接入的每個用戶端驗證它所具有的操作權限。

2.第二層架構主要完成大多少的核心服務功能,如SQL接口,并完成緩存的查詢,SQL的分析和優化及部分内置函數的執行。所有跨存儲引擎的功能也在這一層實作,如過程、函數等。在該層,伺服器會解析查詢并建立相應的内部解析樹,并對其完成相應的優化如确定查詢表的順序,是否利用索引等,最後生成相應的執行操作。如果是select語句,伺服器還會查詢内部的緩存。如果緩存空間足夠大,這樣在解決大量讀操作的環境中能夠很好的提升系統的性能。

3.存儲引擎層,存儲引擎真正的負責了MySQL中資料的存儲和提取,伺服器通過API與存儲引擎進行通信。不同的存儲引擎具有的功能不同,這樣我們可以根據自己的實際需要進行選取。

如果你看着很複雜的話,我們再來個簡單點的圖。如果你看上面的描述了解了一些在看下面的圖,你可能更好了解些。

mysql 原理及配置優化

這上面的三層就相比文本存儲的大概三個優點,其實還有最重要的,那就是事物和鎖,涉及并發。

比如: 當資料庫中有多個操作需要修改同一資料時,不可避免的會産生資料的髒讀。這時就需要資料庫具有良好的并發控制能力,這一切在MySQL中都是由伺服器和存儲引擎來實作的。

解決并發問題最有效的方案是引入了鎖的機制,鎖在功能上分為共享鎖(shared lock)和排它鎖(exclusive lock)即通常說的讀鎖和寫鎖。當一個select語句在執行時可以施加讀鎖,這樣就可以允許其它的select操作進行,因為在這個過程中資料資訊是不會被改變的這樣就能夠提高資料庫的運作效率。當需要對資料更新時,就需要施加寫鎖了,不在允許其它的操作進行,以免産生資料的髒讀和幻讀。

注意: 資料庫裡會出現一種死鎖的情況,就是我占着讀鎖,然而寫鎖要我讀鎖裡的資源去寫入東西,但是我讀鎖要讀出寫鎖占着的資源,這樣就互相占着對方的資源而不放形成死鎖了。InnoDB引擎解決死鎖的方案是将持有最少排它鎖的事務進行復原。

鎖有粒度大小,有表級鎖(table lock)和行級鎖(row lock),分别在資料操作的過程中完成行的鎖定和表的鎖定。

表鎖是MySQL中基本的鎖政策,并且是開銷最小的政策。當使用者在對一張表進行寫操作之前,首先獲得寫鎖,于是,它阻塞了其他連結的讀取和寫入操作,隻有寫鎖接觸的時候,其他連結才能獲得讀鎖。

不僅如此,MySQL還設定了鎖的優先級,在操作列隊中MySQL可能會把寫入操作插入到讀取操作之前。

行級鎖可以最大程度的支援并發處理(同時也帶來了最大的鎖開銷)。行級鎖隻在存儲引擎中實作。行級鎖比表鎖更加精确,他把鎖的對象精确到了對象的某一行,但也就意味着需要建立更多的鎖。

注:理論上鎖定的資源越小,鎖定範圍越精确,那麼并發性能就會越高。但是事實上,建立一個資料鎖也會造成系統的開銷,如果系統通過大量的時間來管理鎖,而不是存取資料,系統的性能反而會降低。

事務

事務其實就是一個獨立的工作單元。如果資料庫引擎能夠完成事務中的每一項操作,那麼全組的SQL語句都會被執行,如果任何一條語句因為崩潰或者其他原因無法執行,那麼所有語句都不執行。并且復原到快照。

MySQL大多數事務型的存儲引擎都不是簡單的行級鎖,基于性能的考慮,他們一般都同時實作了多版本并發控制(MVCC)(這個版本控制有點像SVN那樣,和hibernate中的樂觀鎖差不多機制)。它是通過儲存資料中某個時間點的快照來實作的,這樣就保證了每個事務看到的資料都是一緻的。

mysql 的配置優化。

從MySQL 5.5版本開始,InnoDB就是預設的存儲引擎并且它比任何其他存儲引擎的使用都要多得多。

innodb_buffer_pool_size

緩沖池是資料和索引緩存的地方:這個值越大越好,這能保證你在大多數的讀取操作時使用的是記憶體而不是硬碟。一般設定為實體記憶體的80%

max_connections

MySQL的最大連接配接數,增加該值增加mysqld 要求的檔案描述符的數量。如果伺服器的并發連接配接請求量比較大,建議調高此值,以增加并行連接配接數量,當然這建立在機器能支撐的情況下,因為如果連接配接數越多,介于MySQL會為每個連接配接提供連接配接緩沖區,就會開銷越多的記憶體,是以要适當調整該值,不能盲目提高設值。

show variables like ‘max_connections’ 最大連接配接數

show status like ‘max_used_connections’響應的連接配接數

max_used_connections / max_connections * 100% (理想值≈ 85%)

query_cache_size

使用查詢緩沖,MySQL将查詢結果存放在緩沖區中,今後對于同樣的SELECT語句(區分大小寫),将直接從緩沖區中讀取結果。

通過檢查狀态值Qcache_*,可以知道query_cache_size設定是否合理(上述狀态值可以使用SHOW STATUS LIKE ‘Qcache%’獲得)。

query_cache_type指定是否使用查詢緩沖,可以設定為0、1、2,該變量是SESSION級的變量。

query_cache_type設為1即可。在設 置了這個屬性後,MySQL在執行任何SELECT語句之前,都會在它的緩沖區中查詢是否在相同的SELECT語句被執行過,如果有,并且執行結果沒有過 期,那麼就直接取查詢結果傳回給用戶端。但在寫SQL語句時注意,MySQL的查詢緩沖是區分大小寫的,大小寫不一樣它會重新去資料庫查。

雖然不設定查詢緩沖,有時可能帶來性能上的損失,但有一些SQL語句需要實時地查詢資料,或者并不經常使用(可能一天就執行一兩次)。這樣就需要把 緩沖關了。當然,這可以通過設定query_cache_type的值來關閉查詢緩沖,但這就将查詢緩沖永久地關閉了。

在MySQL 5.0中提供了一種可以臨時關閉查詢緩沖的方法:

(1) SELECT SQL_NO_CACHE field1, field2 FROM TABLE1

以上的SQL語句由于使用了SQL_NO_CACHE,是以,不管這條SQL語句是否被執行過,伺服器都不會在緩沖區中查找,每次都會執行它。

我們還可以将my.ini中的query_cache_type設成2,這樣隻有在使用了SQL_CACHE後,才使用查詢緩沖。

(2) SELECT SQL_CALHE * FROM TABLE1

mysql> show global status like ‘qcache%‘;

mysql> show variables like ‘query_cache%‘;

查詢緩存使用率= (query_cache_size – Qcache_free_memory) / query_cache_size * 100%

查詢緩存使用率在25%以下的話說明query_cache_size設定的過大,可适當減小;查詢緩存使用率在80%以上而且Qcache_lowmem_prunes > 50的話說明query_cache_size可能有點小,要不就是碎片太多。

查詢緩存命中率= (Qcache_hits – Qcache_inserts) / Qcache_hits * 100%

命中率很差的話,可能寫操作比較頻繁吧

show status like ‘Slow_queries’//慢查詢的次數 (預設是10秒中就當做是慢查詢,如下圖所示)

  查詢mysql的慢查詢時間

    Show variables like ‘long_query_time’;

  修改mysql 慢查詢時間

    set long_query_time=2//如果查詢時間超過2秒就算作是慢查詢

mysql支援把慢查詢語句記錄到日志檔案中。程式員需要修改my.ini的配置檔案,預設情況下,慢查詢記錄是不開啟的。

  開啟慢查詢記錄的步驟:

  打開 my.ini ,找到 [mysqld] 在其下面添加

  long_query_time = 2

  

  log-slow-queries = D:/mysql/logs/slow.log #設定把日志寫在那裡,可以為空,系統會給一個預設的檔案。

  我們可以從日志中看出哪些查詢語句查詢超過了,你設定的時間。

  然後可以分析你的查詢語句。主要是用explain分析查詢。

使用 EXPLAIN 關鍵字可以模拟優化器執行SQL查詢語句,進而知道MySQL是如何處理你的SQL語句的。這可以幫你分析你的查詢語句或是表結構的性能瓶頸。

線程緩存

線程緩存儲存了和目前連接配接無關的線程,這些線程可以供新連接配接使用。當要求一個新的連接配接時,如果線程緩存中的連接配接能夠被使用時,新的連接配接就不會被建立,而使用線程緩存中的連接配接。當連接配接關閉時,又會将該線程放回到線程緩存中(前提是線程緩存中有可用的空間)。

參數thread_cache_size用于控制線程緩存的大小,預設值為0,表示沒有線程緩存,這個參數為動态參數可以随時更改,如下:

mysql> show variables like ‘thread_cache_size’;

+——————-+——-+

| Variable_name | Value |

+——————-+——-+

| thread_cache_size | 0 |

+——————-+——-+

通過 Threads_cached 和 Threads_created 狀态變量來監控已緩存的線程數和已建立的線程數。當系統有大量的連接配接時,根據Threads_created或Threads_connected狀态變量的值來适當調整線程緩存的大小,以減少線程建立的開銷。

MySQL線程緩存原理與連接配接池原理相似。

innodb_log_buffer_size: 這項配置決定了為尚未執行的事務配置設定的緩存。

其實還有很多配置檔案裡的其他屬性,但是我們要學會用 show 去定位和檢視影響我們資料的到底是什麼原因,并且每次改的話最好隻改一個配置項,這樣才能知道我們改的影響有多大。