(1)避免like的參數以通配符開頭時java
儘可能避免Like的參數以通配符開頭,不然數據庫引擎會放棄使用索引而進行全表掃描。mysql
以通配符開頭的sql語句,例如:select * from t_credit_detail where Flistid like '%0'\G算法
這是全表掃描,沒有使用到索引,不建議使用。sql
不以通配符開頭的sql語句,例如:select * from t_credit_detail where Flistid like '2%'\G數據庫
很明顯,這使用到了索引,是有範圍的查找了,比以通配符開頭的sql語句效率提升很多。後端
(2) 避免where條件不符合最左前綴原則。最左前綴原則:mysql會一直向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引,d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整(IN和=能夠亂序)。緩存
(3) 使用!= 或 <> 操做符時服務器
儘可能避免使用!= 或 <>操做符,不然數據庫引擎會放棄使用索引而進行全表掃描。使用>或<會比較高效。網絡
select * from t_credit_detail where Flistid != '2000000608201108010831508721'\G架構
(4) 避免索引列參與計算
應儘可能避免在 where 子句中對字段進行表達式操做,這將致使引擎放棄使用索引而進行全表掃描。
select * from t_credit_detail where Flistid +1 > '2000000608201108010831508722'\G
(5) 避免對字段進行null值判斷
應儘可能避免在where子句中對字段進行null值判斷,不然將致使引擎放棄使用索引而進行全表掃描,如: 低效:select * from t_credit_detail where Flistid is null ;
能夠在Flistid上設置默認值0,確保表中Flistid列沒有null值,而後這樣查詢: 高效:select * from t_credit_detail where Flistid =0;
(6) 避免使用or來鏈接條件
應儘可能避免在where子句中使用or來鏈接條件,不然將致使引擎放棄使用索引而進行全表掃描,如: 低效:select * from t_credit_detail where Flistid = '2000000608201108010831508721' or Flistid = '10000200001';
能夠用下面這樣的查詢代替上面的 or 查詢: 高效:select from t_credit_detail where Flistid = '2000000608201108010831508721' union all select from t_credit_detail where Flistid = '10000200001';
在解析的過程當中,會將'*' 依次轉換成全部的列名,這個工做是經過查詢數據字典完成的,這意味着將耗費更多的時間。
因此,應該養成一個須要什麼就取什麼的好習慣。
任何在Order by語句的非索引項或者有計算表達式都將下降查詢速度。
方法:1.重寫order by語句以使用索引;2.爲所使用的列創建另一個索引 3.絕對避免在order by子句中使用表達式。
提升GROUP BY 語句的效率, 能夠經過將不須要的記錄在GROUP BY 以前過濾掉(以下例,先用where語句過濾掉一部分數據)
低效:
SELECT JOB , AVG(SAL) FROM EMP GROUP by JOB HAVING JOB = ‘PRESIDENT' OR JOB = ‘MANAGER'
高效:
SELECT JOB , AVG(SAL) FROM EMP WHERE JOB = ‘PRESIDENT' OR JOB = ‘MANAGER' GROUP by JOB
五、用 exists 代替 in
不少時候用 exists 代替 in 是一個好的選擇: select num from a where num in(select num from b) 用下面的語句替換: select num from a where exists(select 1 from b where num=a.num)
儘量的使用 varchar/nvarchar 代替 char/nchar ,由於首先變長字段存儲空間小,能夠節省存儲空間,其次對於查詢來講,在一個相對較小的字段內搜索效率顯然要高些。
SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID
可改成:
SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10
UNION ALL不執行SELECT DISTINCT函數,這樣就會減小不少沒必要要的資源。(UNION ALL容許重複)
若是應用程序有不少JOIN 查詢,你應該確認兩個表中Join的字段是被建過索引的。這樣,MySQL內部會啓動爲你優化Join的SQL語句的機制。
並且,這些被用來Join的字段,應該是相同的類型的。例如:若是你要把 DECIMAL 字段和一個 INT 字段Join在一塊兒,MySQL就沒法使用它們的索引。對於那些STRING類型,還須要有相同的字符集才行。(兩個表的字符集有可能不同)
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons INNER JOIN Orders ON Persons.Id_P = Orders.Id_P ORDER BY Persons.LastName
不少數據庫系統性能不理想是由於系統沒有通過總體優化,存在大量性能低下的SQL 語句。這類SQL語句性能很差的首要緣由是缺少高效的索引。沒有索引除了致使語句自己運行速度慢外,更是致使大量的磁盤讀寫操做,使得整個系統性能都受之影響而變差。解決這類系統的首要辦法是優化這些沒有索引或索引不夠好的SQL語句。優化SQL語句的關鍵是儘量減小語句的logical reads(是指語句執行時須要訪問的單位爲8K的數據頁) logical reads 越少,其須要的內存和CPU時間也就越少,語句執行速度就越快。不言而喻,索引的最大好處是它能夠極大減小SQL語句的logical reads數目,從而極大減小語句的執行時間。建立索引的關鍵是索引要可以大大減小語句的logical reads。一個索引好很差,主要看它減小的logical reads多很少。 運行set statistics io命令能夠獲得SQL語句的logical reads信息。Logical reads中包含該語句從內存數據緩衝區中訪問的頁數和從物理磁盤讀取的頁數。而physical reads表示那些沒有駐留在內存緩衝區中須要從磁盤讀取的數據頁。
1對出如今where子句中的字段加索引
全表掃描的性能一般是不好的,要儘可能避免。 建立索引的技巧之一是對常常出如今where條件中的字段建立索引
2.組合索引
單字段索引是指只有一個字段的索引,而組合索引指有多個字段構成的索引。若是where語句中有多個字段,那麼能夠考慮建立組合索引。組合索引中字段的順序是很是重要的,越是惟一的字段越是要靠前。(根據最左前綴準則)另外,不管是組合索引仍是單個列的索引,儘可能不要選擇那些惟一性很低的字段。因此若是對單字段進行索引,建議使用set statistics profile(會輸出語句的執行計劃)來驗證索引確實被充分使用。logical reads越少的索引越好。
3.覆蓋索引
覆蓋索引可以使得語句不須要訪問表僅僅訪問索引就可以獲得全部須要的數據。 由於彙集索引葉子節點就是數據因此無所謂覆蓋與否,因此覆蓋索引主要是針對非彙集索引而言。執行計劃中除了index seek外,還有一個Bookmark Lookup關鍵字。 Bookmark Lookup表示語句在訪問索引後還須要對錶進行額外的Bookmark Lookup操做才能獲得數據。也就是說爲獲得一行數據起碼有兩次IO,一次訪問索引,一次訪問基本表。 若是語句返回的行數不少,那麼Bookmark Lookup操做的開銷是很大的。 覆蓋索引可以避免昂貴的Bookmark Lookup操做,減小IO的次數,提升語句的性能。 覆蓋索引須要包含select子句和WHERE子句中出現的全部字段。因此建立覆蓋索引是減小logical reads提高語句性能的很是有用的優化技巧。
問題1,是否值得在identity字段(自增字段)上創建彙集索引。
答案取決於identity 字段如何在語句中使用。若是你常常根據該字段搜索返回不多的行,那麼在其上創建索引是值得的。反之若是identity字段根本不多在語句中使用,那麼就不該該對其創建任何索引。
問題2,一個表應該創建多少索引合適。
若是表的80%以上的語句都是讀操做,那麼索引能夠多些。可是不要太多。 特別是不要對那些更新頻繁的表其創建不少的索引。不多表有超過5個以上的索引。過多的索引不但增長其佔用的磁盤空間,也增長了SQL Server 維護索引的開銷。
問題4:爲何SQL Server 在執行計劃中沒有使用你認爲應該使用的索引?緣由是多樣的。
一種緣由是該語句返回的結果超過了表的20%數據,使得SQL Server 認爲scan比seek更有效。另外一種緣由多是表字段的statistics過時了,不能準確反映數據的分佈狀況。你可使用命令UPDATE STATISTICS tablename with FULLSCAN來更新它。只有同步的準確的statistics才能保證SQL Server 產生正確的執行計劃。
問題五、什麼使用匯集索引,何時使用非彙集索引
在SQL Server 中索引有彙集索引和非彙集索引兩種。它們的主要差異是前者的索引葉子就是數據自己,然後者的葉子節點包含的是指向數據的書籤(即數據行號或彙集索引的key)。來自彙集索引的鍵值由全部非彙集索引做爲查找鍵使用,所以存儲在每一個非彙集索引的葉條目內。對一個表而言彙集索引只能有一個,而非彙集索引能夠有多個。只是彙集索引沒有Bookmark Lookup操做。
在建立彙集索引以前,應先了解您的數據是如何被訪問的。可考慮將彙集索引用於:
彙集索引不適用於:
MySQL主從複製是其最重要的功能之一。主從複製是指一臺服務器充當主數據庫服務器,另外一臺或多臺服務器充當從數據庫服務器,主服務器中的數據自動複製到從服務器之中。MySQL主從複製的基礎是主服務器對數據庫修改記錄二進制日誌,從服務器經過主服務器的二進制日誌自動執行更新。
主從複製的做用
一、作數據的熱備,做爲後備數據庫,主數據庫服務器故障後,可切換到從數據庫繼續工做,避免數據丟失。
二、架構的擴展。業務量愈來愈大,I/O訪問頻率太高,單機沒法知足,此時作多庫的存儲,下降磁盤I/O訪問的頻率,提升單個機器的I/O性能。(請求發到多部機子上)
三、讀寫分離,使數據庫能支撐更大的併發。一主多從的部署方案,將涉及數據寫的操做放在Master端操做,而將數據讀的操做分散到衆多的Slave當中。下降了Master的負載,提升數據寫入的響應效率;多臺從服務器提供讀,分擔了請求,提升了讀的效率。在報表中尤爲重要。因爲部分報表sql語句很是的慢,致使鎖表,影響前臺服務。若是前臺使用master,報表使用slave,那麼報表sql將不會形成前臺鎖,保證了前臺速度。
主從複製的原理
1.數據庫有個bin-log二進制文件,記錄了全部sql語句。
2.咱們的目標就是把主數據庫的bin-log文件的sql語句複製過來。
3.讓其在從數據的relay-log重作日誌文件中再執行一次這些sql語句便可。
主從複製步驟以及涉及的線程:
一:主庫db的更新事件(update、insert、delete)被寫到binlog
二:從庫發起鏈接,鏈接到主庫
三:此時主庫建立一個binlog dump thread線程,把binlog的內容發送到從庫
四:從庫啓動以後,建立一個I/O線程,讀取主庫傳過來的binlog內容並寫入到relay log.
五:還會建立一個SQL線程,從relay log裏面讀取內容,從Exec_Master_Log_Pos位置開始
1.binlog輸出線程:每當有從庫鏈接到主庫的時候,主庫都會建立一個線程輸出binlog,而後發送binlog內容到從庫。
2.從庫I/O線程:當START SLAVE語句在從庫開始執行以後,從庫建立一個I/O線程,該線程鏈接到主庫並請求主庫發送binlog裏面的更新記錄到從庫上。(從主庫先傳輸下來)從庫I/O線程讀取主庫的binlog輸出線程發送的更新並拷貝這些更新到本地文件,其中包括relay log文件(再更新relay log)。
3.從庫的SQL線程:從庫建立一個SQL線程,這個線程讀取從庫I/O線程寫到relay log的更新事件並執行。
作主從後主服務器掛了怎麼辦
假設發生了突發事件,master宕機,如今的需求是要將從庫提高爲主庫,另一個爲從庫:
1.確保全部的從庫的relay log所有更新完畢,在每一個從庫上執行stop slave io_thread; show processlist;直到看到Has read all relay log,則表示從庫更新都執行完畢了
2.登錄全部從庫,查看master.info文件,選擇一個從庫爲新的主庫
3.登錄該從庫,執行stop slave; 並進入數據庫目錄,刪除master.info和relay-log.info文件, 配置my.cnf文件,開啓log-bin,若是有log-slaves-updates和read-only則要註釋掉,執行reset master
4.建立用於同步的用戶並受權slave,同第五大步驟
5.登陸另一臺從庫,執行stop slave中止同步
6.根據第七大步驟鏈接到新的主庫
7.執行start slave;
8.修改新的master數據,測試slave是否同步更新
主從複製延遲
主庫針對讀寫操做,順序寫 binlog,從庫單線程去主庫讀"寫操做的binlog",從庫取到 binlog在本地原樣執行(隨機寫),來保證主從數據邏輯上一致.mysql的主從複製都是單線程的操做,主庫對全部DDL和DML產生 binlog,binlog是順序寫,因此效率很高,slave的Slave_IO_Running線程到主庫取日誌,效率比較高,下一步問題來了,slave的 slave_sql_running線程將主庫的 DDL和DML操做在 slave實施。DML,DDL的IO操做是隨機的,不能順序的,成本高不少,還有可能slave上的其餘查詢產生 lock,因爲 slave_sql_running也是單線程的,因此 一個 DDL卡住了,需求需求執行一段時間,那麼全部以後的DDL會等待這個 DDL執行完纔會繼續執行,這就致使了延遲.因爲master能夠併發,Slave_sql_running線程卻不能夠,因此主庫執行 DDL需求一段時間,在slave執行相同的DDL時,就產生了延遲.
主從同步延遲產生緣由
當主庫的TPS併發較高時,產生的DDL數量超過Slave一個 sql線程所能承受的範圍,那麼延遲就產生了,固然還有就是可能與 slave的大型 query語句產生了鎖等待
首要緣由:數據庫在業務上讀寫壓力太大,CPU計算負荷大,網卡負荷大,硬盤隨機IO過高
次要緣由:讀寫 binlog帶來的性能影響,網絡傳輸延遲
主從同步延遲解決方案
架構方面:mysql壓力變小,延遲天然會變小
1.業務的持久化層的實現採用分庫架構,mysql服務可平行擴展分散壓力
2.單個庫讀寫分離,一主多從,主寫從讀,分散壓力。
3.服務的基礎架構在業務和mysql之間加放 cache層
4.不一樣業務的mysql放在不一樣的機器
5.使用比主加更好的硬件設備做slave
MySQL的主從複製和MySQL的讀寫分離二者有着緊密聯繫,首先部署主從複製,只有主從複製完了,才能在此基礎上進行數據的讀寫分離。讀寫分離就是隻在主服務器上寫,只在從服務器上讀,基本的原理是讓主數據庫處理事務性查詢,而從數據庫處理select查詢,數據庫複製被用來把事務性查詢致使的改變動新同步到集羣中的從數據庫,即主從複製。
1.基於程序代碼內部實現
在代碼中根據select,insert進行路由分類,這類方法也是目前生產環境應用最普遍的,優勢是性能好,由於在程序代碼中實現,不須要曾加額外的設備做爲硬件開支,缺點是須要開發人員來實現,運維人員無從下手。
2.基於中間代理層實現
代理通常位於客戶端和服務器之間,代理服務器接到客戶端請求後經過判斷後轉發到後端數據庫,有兩個表明性程序。
(1)mysql-proxy 爲mysql開源項目,經過其自帶的lua腳本進行SQL判斷,雖然是mysql的官方產品,可是mysql官方不建議將其應用到生產環境
(2)Amoeba (變形蟲)由陳思儒開發,曾就任與阿里巴巴,該程序由java語言進行開發,阿里巴巴將其應用於生成環境,它不支持事物和存儲過程
經過程序代碼實現mysql讀寫分離天然是一個不錯的選擇,可是並非全部的應用都適合在程序代碼中實現讀寫分離,像一些大型複雜的java應用,若是在程序代碼中實現讀寫分離對代碼改動就較大,像這種應用通常會考慮使用代理層來實現。
MySQL Proxy是一個處於你的client端和MySQL server端之間的簡單程序,它能夠監測、分析或改變它們的通訊。它使用靈活,沒有限制,常見的用途包括:負載平衡,故障、查詢分析,查詢過濾和修改等等。MySQL Proxy就是這麼一箇中間層代理,簡單的說,MySQL Proxy就是一個鏈接池,負責將前臺應用的鏈接請求轉發給後臺的數據庫,而且經過使用lua腳本,能夠實現複雜的鏈接控制和過濾,從而實現讀寫分離和負載平衡。對於應用來講,MySQL Proxy是徹底透明的,應用則只須要鏈接到MySQL Proxy的監聽端口便可。固然,這樣proxy機器可能單點失效,但徹底可使用多個proxy機器作爲冗餘,在應用服務器的鏈接池配置中配置到多個proxy的鏈接參數便可。MySQL Proxy更強大的一項功能是實現「讀寫分離」,基本原理是讓主數據庫處理事務性查詢,讓從庫處理SELECT查詢。數據庫複製被用來把事務性查詢致使的變動同步到集羣中的從庫。
讀寫分離的好處:
1)物理服務器增長,負荷增長 2)主從只負責各自的寫和讀,極大程度的緩解X鎖和S鎖爭用 3)從庫可配置myisam引擎,提高查詢性能以及節約系統開銷 4)從庫同步主庫的數據和主庫直接寫仍是有區別的,經過主庫發送來的binlog恢復數據,可是,最重要區別在於主庫向從庫發送binlog是異步的,從庫恢復數據也是異步的 5)讀寫分離適用與讀遠大於寫的場景,若是隻有一臺服務器,當select不少時,update和delete會被這些select訪問中的數據堵塞,等待select結束,併發性能不高。 對於寫和讀比例相近的應用,應該部署雙主相互複製 6)能夠在從庫啓動是增長一些參數來提升其讀的性能,例如--skip-innodb、--skip-bdb、--low-priority-updates以及--delay-key-write=ALL 固然這些設置也是須要根據具體業務需求來定得,不必定能用上 7)分攤讀取。假如咱們有1主3從,不考慮上述1中提到的從庫單方面設置,假設如今1 分鐘內有10條寫入,150條讀取。那麼,1主3從至關於共計40條寫入,而讀取總數沒變,所以平均下來每臺服務器承擔了10條寫入和50條讀取(主庫不 承擔讀取操做)。所以,雖然寫入沒變,可是讀取大大分攤了,提升了系統性能。另外,當讀取被分攤後,又間接提升了寫入的性能。因此,整體性能提升了,說白 了就是拿機器和帶寬換性能。MySQL官方文檔中有相關演算公式:官方文檔 見6.9FAQ之「MySQL複製可以什麼時候和多大程度提升系統性能」 8)MySQL複製另一大功能是增長冗餘,提升可用性,當一臺數據庫服務器宕機後能經過調整另一臺從庫來以最快的速度恢復服務,所以不能光看性能,也就是說1主1從也是能夠的。
表分區其實就是將一張大數據量表中的數據按照不一樣的分區策略分配到不一樣的系統分區、硬盤或是不一樣的服務器設備上,實現數據的均衡分配,這樣作的好處是均衡大數據量數據到不一樣的存儲介子中,這樣每一個分區均攤了一部分數據,而後能夠定位到指定的分區中,對數據表進行需求操做,另外,也方便管理水錶,好比要刪除某個時間段的數據,就能夠按照日期分區,而後直接刪除該日期分區便可,而且效率相對於傳統的DELETE數據效率高不少,這裏以Mysql爲例進行說明。
分區和分表的區別:
分區和分錶針對的都是數據表,而分表是真正的生成數據表,是將一張大數據量的表分紅多個小表實現數據均衡;
分區並非生成新的數據表,而是將表的數據均衡分攤到不一樣的硬盤,系統或是不一樣服務器存儲介子中,實際上仍是一張表。
另外,分區和分表均可以作到將表的數據均衡到不一樣的地方,提升數據檢索的效率,下降數據庫的頻繁IO壓力值,
分區的優勢以下:
一、相對於單個文件系統或是硬盤,分區能夠存儲更多的數據;
二、數據管理比較方便,好比要清理或廢棄某年的數據,就能夠直接刪除該日期的分區數據便可;
三、精準定位分區查詢數據,不須要全表掃描查詢,大大提升數據檢索效率;
四、可跨多個分區磁盤查詢,來提升查詢的吞吐量;
五、在涉及聚合函數查詢時,能夠很容易進行數據的合併;
表的分區的原理理解起來比較簡單,其實就是把一張大數據量的表,根據分區策略進行分區,分區設置完成以後,由數據庫自身的儲存引擎來實現分發數據到指定的分區中去,正如上圖所示,一張數據表被分紅了n個分區,而且分區被放入到不一樣的介子disk中,每一個disk中包含自少一個分區,這就實現了數據的均衡以及經過跨分區介子檢索提升了總體的數據操做IO吞吐率。
表分區的策略:
目前在MySql中支持四種表分區的方式,分別爲HASH、RANGE、LIST及KEY,固然在其它的類型數據庫中,分區的實現方式略有不一樣,可是分區的思想原理是相同,具體以下。
Hash:HASH分區主要用來確保數據在預先肯定數目的分區中平均分佈,而在RANGE和LIST分區中,必須明確指定一個給定的列值或列值集合應該保存在哪一個分區中,而在HASH分區中,MySQL自動完成這些工做,你所要作的只是基於將要被哈希的列值指定一個列值或表達式,以及指定被分區的表將要被分割成的分區數量。
CREATE TABLE t_product_item ( id int(7) not null, title varchar(40) not null, subtitle varchar(60) null, price double not null, imgurl varchar(70) not null, producttype int(2) not null, createtime datetime not null )ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY HASH(YEAR(createtime)) //指定Hash的列值或表達式 PARTITIONS 10 //指定分區數量
Range:基於屬於一個給定連續區間的列值,把多行分配給同一個分區,這些區間要連續且不能相互重疊,使用VALUES LESS THAN操做符來進行定義。
CREATE TABLE t_product_item ( id int(7) not null, title varchar(40) not null, subtitle varchar(60) null, price double not null, imgurl varchar(70) not null, producttype int(2) not null, createtime datetime not null )ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY RANGE(producttype) ( //指定producttype做爲range劃分的列,並對值進行區域劃分 PARTITIONP0 VALUES LESS THAN(2), PARTITIONP1 VALUES LESS THAN(4), PARTITIONp2 VALUES LESS THAN(6), PARTITIONp3 VALUES LESS THAN MAXVALUE );
List:相似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇分區的。LIST分區經過使用「PARTITION BY LIST(expr)」來實現,其中「expr」 是某列值或一個基於某個列值、並返回一個整數值的表達式,而後經過「VALUES IN (value_list)」的方式來定義每一個分區,其中「value_list」是一個經過逗號分隔的整數列表。
CREATE TABLE t_product_item ( id int(7) not null, title varchar(40) not null, subtitle varchar(60) null, price double not null, imgurl varchar(70) not null, producttype int(2) not null, createtime datetime not null )ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY LIST(producttype) ( //利用枚舉出列值或表達式-->整型集合 PARTITIONP0 VALUES IN (0,1), //利用IN進行分區 PARTITIONP1 VALUES IN (2,3), PARTITIONP2 VALUES IN (4,5), PARTITIONP3 VALUES IN (6,7,8,9,10,11,12) )
Key:相似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL 服務器提供其自身的哈希函數。必須有一列或多列包含整數值。
表分區的注意:
一、引擎的統一
在對同一個表進行分區時,必須保證數據表的引擎相同,好比:不能對一個分區的表爲InnoDB,而另外一個分區的引擎爲MySIAM。
二、分區關聯性
在對數據表分區時,不能只對數據進行分區,須要連同其對應的索引等屬性一同分區動做,某種程度上能夠保持數據屬性的完整。
三、分區的級別
對錶進行分區以後,若是某個分區中的數據量依然很大或是增加迅速,那麼你一樣能夠再進行子分區操做,將該數據再分區到其它分區中。另外,若是在一個分區中使用了子分區,那麼其它的子分區也必須定義。
四、LIST分區
LIST分區沒有相似如「VALUESLESS THAN MAXVALUE」這樣的包含其餘值在內的定義。將要匹配的任何值都必須在值列表中找到。
五、Linear線性
分區策略KEY和HASH都支持使用線性LINEAR的算法,也就是分區的編號是經過2的冪(powers-of-two)算法獲得,而不是經過模數算法。
垂直分表
1.減小記錄的字段可以使內存加載更多行數據,有利於查詢。
2.受限於操做系統中的文件大小限制。
切分原則:把不經常使用或業務邏輯不緊密或存儲內容比較多的字段分到新的表中可以使表存儲更多數據。另外垂直分割可使得數據行變小,一個數據頁就能存放更多的數據,在查詢時就會減小I/O次數。其缺點是須要管理冗餘列,查詢全部數據須要join操做。
水平分表
1.隨着數據量的增大,table行數巨大,查詢的效率愈來愈低。表很大,分割後能夠下降在查詢時須要讀的數據和索引的頁數,同時也下降了索引的層數,提升查詢速度。
2.一樣受限於操做系統中的文件大小限制,數據量不能無限增長,當到達必定容量時,須要水平切分以下降單表(文件)的大小。
切分原則:
增量區間或散列或其餘業務邏輯。使用哪一種切分方法要根據實際業務邏輯判斷:好比對錶的訪問可能是近期產生的新數據,歷史數據訪問較少,能夠考慮根據時間增量把數據按照必定時間段(好比每一年)切分。若是對錶的訪問較均勻,沒有明顯的熱點區域,則能夠考慮用範圍(好比每500w一個表)或普通Hash或一致性Hash來切分。
全局主鍵問題:本來依賴數據庫生成主鍵(好比自增)的表在拆分後須要本身實現主鍵的生成,由於通常拆分規則是創建在主鍵上的(拆分後仍然要保證主鍵在全局的惟一性),因此在插入新數據時須要肯定主鍵後才能找到存儲的表。