數據庫優化
數據庫優化分為以下幾個大類:
SQL語句優化
事務優化
表結構優化
使用緩存和NoSQL數據庫方式存儲,如//Redis來緩解高并發下的數據庫查詢的壓力
減少數據庫操作次數,盡量使用數據庫訪問驅動的批處理方法
不常使用的數據遷移備份,避免每次都在海量數據中去檢索
SQL語句優化
數據庫調優在一般情況下都是SQL調優,那么,應該如何進行SQL調優呢?
低性能SQL語句定位(找到有問題的SQL語句)
使用執行計劃
執行計劃,就是顯示數據庫引擎對于SQL語句的執行的詳細情況,其中包含了是否使用索引,使用什么索引,使用的索引的相關信息等。
執行計劃包含的信息:
id:由一組數字組成。表示一個查詢中各個子查詢的執行順序;id相同執行順序由上至下,id不同,id值越大優先級越高,越先被執行。id為null時表示一個結果集,不需要使用它查詢,常出現在包含union等查詢語句中。
:每個子查詢的查詢類型,一些常見的查詢類型。
id
1
不包含任何子查詢或union等查詢
2
包含子查詢最外層查詢就顯示為
3
在或 where字句中包含的查詢
4
from字句中包含的查詢
5
UNION
出現在union后的查詢語句中
6
UNION
從UNION中獲取結果集
type:(非常重要,可以看到有沒有走索引) 訪問類型all 掃描全表數據index 遍歷索引range 索引范圍查找 在子查詢中使用 ref
在子查詢中使用
對Null進行索引的優化的 ref
使用全文索引ref 使用非唯一索引查找數據 在join查詢中使用 NOT NULL索引關聯。
:可能使用的索引,注意不一定會使用。查詢涉及到的字段上若存在索引,則該索引將被列出來。當該列為 NULL時就要考慮當前的SQL是否需要優化了。
key:顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示為NULL。查詢中若使用了覆蓋索引,則該索引僅出現在key列表中
:索引長度
ref:表示上述表的連接匹配條件,即哪些列或常量被用于查找索引列上的值
rows:返回估算的結果集數目,并不是一個準確的值。
extra:執行情況的描述和說明,extra的信息非常豐富,常見的有:Using index 使用覆蓋索引Using where 使用了用where子句來過濾結果集Using 使用文件排序,使用非索引列進行排序時出現,非常消耗性能,盡量優化。Using 使用了臨時表 sql優化的目標可以參考阿里開發手冊注: 只能解釋操作,其他操作要重寫為后查看執行計劃。
2.如果有告警信息,查看告警信息 show
3.查看SQL涉及的表結構和索引信息
4.根據執行計劃,思考可能的優化點
5.按照可能的優化點執行表結構變更、增加索引、SQL改寫等操作
6.查看優化后的執行時間和執行計劃
7.如果優化效果不明顯,重復第四步操作
從以上步驟會發現執行計劃很多參數都是面向索引的,說明索引對SQL優化是有很大影響的,那么,什么是索引呢?
數據庫索引:索引是一種特殊的文件,它們包含著對數據表里所有記錄的引用指針。索引是一種數據結構。數據庫索引,是數據庫管理系統中一個排序的數據結構,以協助快速查詢、更新數據庫表中數據。索引的實現通常使用B樹及其變種B+樹。更通俗的說,索引就相當于目錄。為了方便查找書中的內容,通過對內容建立索引形成目錄。索引是一個文件,它是要占據物理空間的。
索引從實現上來說,分成兩種:聚集索引(聚簇索引)和輔助索引(也叫二級索引或者非聚集索引、非聚簇索引)
聚簇索引:按照每張表的主鍵構造一棵B+樹,同時葉子節點中存放的就是整張表的行記錄數據,也將聚簇索引的葉子節點稱為數據頁。聚簇索引將數據存儲與索引放到了一塊,找到索引也就找到了數據。
輔助索引:在聚簇索引之上創建的索引稱之為輔助索引,輔助索引葉子節點存放的不再是行的數據,而是主鍵值。輔助索引將數據存儲與索引分開,索引結構的葉子節點指向了數據的對應行。
一般建表會用一個自增主鍵做聚簇索引,沒有的話MySQL會默認創建,但是這個主鍵如果更改的話代價較高,故自增ID不能頻繁。我們日常工作中,根據實際情況自行添加的索引都是輔助索引,輔助索引就是一個為了尋找主鍵索引的二級索引,找到主鍵索引再通過主鍵索引找數據。
從功能上來說,分為六種:普通索引:最基本的索引,沒有任何約束唯一索引:與普通索引類似,但具有唯一性約束主鍵索引:特殊的唯一索引,不允許有空值復合索引:將多個列組合在一起創建索引,可以覆蓋多個列外鍵索引:只有類型的表才可以使用外鍵索引,保證數據的一致性,完整性和實現級聯操作全文索引:MySQL全文索引在5.7之前只支持英文,5.7之后內置了ngram全文檢索插件mysql數據庫查看表內容,用來支持中文分詞,對和引擎都有效,不過一般更傾向使用全文索引引擎(ES,Solr)
注:主鍵就是唯一索引,但是唯一索引不一定是主鍵,唯一索引可以為空,但是空值只能有一個,主鍵不能為空。
設置主鍵時,會自動生成一個唯一索引,如果之前沒有聚集索引,那么主鍵就是聚集索引。沒有設置主鍵時mysql數據庫查看表內容,會選擇一個不為空的唯一索引作為聚集索引,如果還沒有,那就生成一個隱式的6字節的索引。
關于索引的內容暫且到此,本文以數據庫優化為核心,具體的底層原理在《MySQL架構體系》一文中詳細闡述
SQL語句優化
使用連接(Join)來代替子查詢(Sub-)
連接之所以更有效率一些,是因為MySQL不需要在內存中創建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作。
UNION ALL能滿足業務需要不要使用UNION
UNION會自動壓縮多個結果集合中的重復結果,而UNION ALL則將所有的結果全部顯示出來,不管是不是重復。
WHERE子句盡量避免使用!=或操作符
在WHERE子句中使用!=或操作符,查詢條件不會使用索引,會進行全表查詢。即影響查詢效率。
WHERE子句使用OR優化
通常情況我們可以使用UNION ALL 或 UNION的方式替換OR會得到更好的效果。因為WHERE子句中使用了OR,將不會使用索引。
WHERE子句使用IN或NOT IN優化
IN和NOT IN也要慎用,否則可能會導致全表掃描
可用以下方案替換:
· AND 替換 IN
· 替換 IN
·LEFT JOIN 替換 IN
WHERE子句使用IS NULL 或IS NOT NULL優化
在WHERE子句中使用IS NULL或IS NOT NULL判斷,索引將被放棄使用,會進行全表查詢。
一定不要使用 * FROM
WHERE子句避免對字段進行表達式操作
數據庫索引優化
1.索引覆蓋與回表查詢如果要查詢的字段都建立過索引,那么索引會直接在索引表中查詢而不會訪問原始數據(否則只要有一個字段沒有建立索引就會做全表掃描),這叫索引覆蓋。因此我們需要盡可能的在后只寫必要的查詢字段,以增加索引覆蓋的幾率。(不要想著為每個字段建立索引,因為優先使用索引的優勢就在于其體積小。)回表查詢:先定位主鍵值,再根據主鍵值定位行記錄
hash索引任何時候都避免不了回表查詢數據,而B+樹在符合某些條件的時候可以只通過索引完成查詢。(具體留《MySQL架構體系》一文中補充,挖坑待填)
2.創建索引的原則
·較頻繁作為查詢條件的字段才去創建索引
·更新頻繁字段不適合創建索引
·不能有效區分數據的列不適合做索引列(如性別)
·定義有外鍵的數據列一定要建立索引
·盡量擴展索引不要新建索引
事務優化
什么是數據庫事務?事務是一個不可分割的數據庫操作序列,也是數據庫并發控制的基本單位,其執行的結果必須使數據庫從一種一致性狀態變到另一種一致性狀態。事務是邏輯上的一組操作,要么都執行,要么都不執行。
數據庫事務的四大特性
ACID
原子性:事務是最小的執行單位,不允許分割。事務的原子性確保動作要么全部完成,要么完全不起作用一致性:執行事務前后,數據保持一致,多個事務對同一個數據讀取的結果是相同的隔離性:并發訪問數據庫時,一個用戶的事務不被其他事務所干擾,各并發事務之間數據庫是獨立的持久性:一個事務被提交之后。它對數據庫中數據的改變是持久的,即使數據庫發生故障也不應該對其有任何影響
臟讀、幻讀、不可重復讀臟讀(Drity Read):某個事務已更新一份數據,另一個事務在此時讀取了同一份數據,由于某些原因,前一個了操作,則后一個事務所讀取的數據就會是不正確的。不可重復讀(Non- read):在一個事務的兩次查詢之中數據不一致,這可能是兩次查詢過程中間插入了一個事務更新的原有的數據?;米x( Read):在一個事務的兩次查詢中數據筆數不一致,例如有一個事務查詢了幾列(Row)數據,而另一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。
事務的隔離級別為了達到事務的四大特性,數據庫定義了4種不同的事務隔離級別:
READ-(讀取未提交):最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致臟讀、幻讀或不可重復讀。
READ-(讀取已提交):允許讀取并發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生。
-READ(可重復讀):對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生。
(可串行化):最高的隔離級別,完全服從ACID的隔離級別。所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。
Mysql 默認采用的 隔離級別 默認采用的 隔離級別
隔離級別與鎖的關系在Read 級別下,讀取數據不需要加共享鎖,這樣就不會跟被修改的數據上的排他鎖沖突
在Read 級別下,讀操作需要加共享鎖,但是在語句執行完以后釋放共享鎖;
在 Read級別下,讀操作需要加共享鎖,但是在事務提交之前并不釋放共享鎖,也就是必須等待事務執行完畢以后才釋放共享鎖。
是限制性最強的隔離級別,因為該級別鎖定整個范圍的鍵,并一直持有鎖,直到事務完成。
通常,對于絕大多數的應用程序來說,可以優先考慮將數據庫系統的隔離級別設置為讀已提交,這能夠避免臟讀的同時保證較好的并發性能。盡管這種事務隔離級別會導致不可重復讀、虛讀和第二類丟失更新等并發問題。但較為科學的做法是在可能出現這類問題的個別場合,由應用程序主動采取悲觀鎖或樂觀鎖來進行事務控制。
表結構優化
數據庫表優化
·設計規范化表,消除數據冗余數據庫三范式第一范式:屬性(字段)的原子性約束,要求屬性具有原子性,不可再分割第二范式:記錄的惟一性約束,要求記錄有惟一標識,每條記錄需要有一個屬性來做為實體的唯一標識第三范式:屬性(字段)冗余性的約束,即任何字段不能由其他字段派生出來,在通俗點就是:主鍵沒有直接關系的數據列必須消除(消除的辦法就是再創建一個表來存放他們,當然外鍵除外)
滿足范式的表,稱為規范化表如果數據庫設計達到了完全的標準化,則把所有的表通過關鍵字連接在一起時,不會出現任何數據的復本()。標準化的優點是明顯的,它避免了數據冗余,自然就節省了空間,也對數據的一致性()提供了根本的保障,杜絕了數據不一致的現象,同時也提高了效率。
·適當的冗余,增加計算列數據庫設計的實用原則是:在數據冗余和處理速度之間找到合適的平衡點滿足范式的表一定是規范化的表,但不一定是最佳的設計。很多情況下會為了提高數據庫的運行效率,常常需要降低范式標準:適當增加冗余,達到以空間換時間的目的。合理的冗余可以分散數據量大的表的并發壓力,也可以加快特殊查詢的速度,冗余字段可以有效減少數據庫表的連接,提高效率。(例如合計、總量這種由其他字段計算出來的列)
·字段設計優化字段是數據庫最基本的單位,其設計對性能的影響是很大的。需要注意如下:
A、數據類型盡量用數字型,數字型的比較比字符型的快很多。
B、數據類型盡量小,這里的盡量小是指在滿足可以預見的未來需求的前提下的。
C、盡量不要允許NULL,除非必要,可以用NOT NULL+代替。
D、少用TEXT和IMAGE,二進制字段的讀寫是比較慢的,而且,讀取的方法也不多,大部分情況下最好不用。
E、自增字段要慎用,不利于數據遷移
2.讀寫分離(解決數據庫讀性能瓶頸)
將數據庫分為了主從庫,一個主庫用于寫數據,多個從庫完成讀數據的操作,主從庫之間通過某種機制進行數據的同步。(用來解決數據庫的讀性能瓶頸)
常見的數據庫瓶頸:數據容量的瓶頸最好的解決辦法:數據庫水平切分
3.數據庫水平切分(解決數據容量瓶頸)
通過算法,將數據庫進行分割的架構。一個水平切分集群中的每個數據庫,通常被稱為一個"分片"。每一個分片中的數據沒有重合,所有分片中的數據并集組成全部數據。
4.數據庫垂直切分(降低單節點數據庫的負載)
根據業務來拆分數據庫,同一類業務的數據表拆分到一個獨立的數據庫,另一類的數據表拆分到其他數據庫。垂直切分可以降低單節點數據庫的負載,不能解決縮表問題通俗來講:水平拆分行,行數據拆分到不同的表中,垂直拆分列,表數據拆分到不同表中。
MySQL單表記錄超過2000萬,讀寫性能會下降的很快,因此說垂直切分并不能起到縮表的效果。
出處: