Mysql分庫、分表可能帶來的問題與單庫性能優化


參考:https://www.cnblogs.com/lfs2640666960/p/11116962.html

https://blog.csdn.net/cai13070139328/article/details/100099110

 

數據的讀寫分離只是解決了訪問的壓力,但是存儲的壓力沒有解決。

要想解決存儲的壓力就要引入分庫分表。

分庫:

  分庫就是現在你有一個數據庫服務器,數據庫中有兩張表分別是用戶表和訂單表。如果要分庫的話現在需要兩台機器,每個機器上安裝一台數據庫,一台機器上的數據庫放用戶表,一台機器上的數據庫放訂單表。這樣存儲壓力就分擔到兩個服務器上了。

分庫帶來的問題:

  聯表查詢問題,也就是join,之前在一個數據庫里面可以用上join,用一條SQL語句就可以聯表查詢得到想要的結果,現在分為多個數據庫join用不上了。比如要查注冊時間在2019年之后用戶的訂單信息,你就需要先去數據庫A中用戶表查詢注冊在2019年之后的信息,然后得到用戶id,再拿這些id去數據庫B訂單表中查詢訂單信息,然后再拼接這些信息返回,所以總體多寫了一些代碼。

  事務問題,現在不同的數據庫事務就不是以前那個簡單的本地事務了,而是分布式事務了,而引入分布式事務也提高了系統的復雜性,並且有些效率不高還會影響性能,例如Mysql XA,或者基於消息中間件實現的分布式事務。

分表:

  如果一張表里面的數據量過大,會嚴重影響性能,這時候就要考慮分表。

  垂直分表:將列進行拆分,將那些不常用的列分到一張表,常用的分到一張表,這樣每張表大小就會變小。垂直分表適合表中存在大量不常用的表。

       垂直分表的影響就是之前只要一個查詢的,現在需要兩次查詢才能拿到分表之前的用戶表信息。

  水平分表:水平分表適合行數很多的表,例如超過了5000萬,有些場景可能超過1000萬就要分表了。

       水平分表帶來了路由問題,也就是按照什么原則分,可以按id范圍、id hash等,或者搞一張表單獨存放路由關系,不過,每次查詢都得查兩次如       果路由表太大,那么路由表又會成為瓶頸。

       帶來的查詢問題:比如要查詢注冊時間最早的前100名用戶,這就等於你得在水平分的每一張表都order by一下注冊時間,並且取100個,然后再       把每個表的100個結果對比一下得到最終結果。 整個操作變的復雜了,以前只需要1個order by操作,現在是多個order by。如果分了20個表,那       么20個order  by可能很耗時,串行執行則更慢。

分庫分表的實現:

  可以在客戶端代碼里面做,也可以使用中間件,這樣客戶端無感知。分庫分表中間件可以使用Mycat。

  參考:https://blog.csdn.net/wt077521/article/details/80469015

     https://blog.csdn.net/weixin_38319645/article/details/81537849

分庫分表分區  怎么選:

  

集群擴容:

  

表的設計:

  表字段避免null值出現,null值很難查詢優化且占用額外的索引空間,推薦默認數字0代替null。

  盡量使用INT而非BIGINT,如果非負則加上UNSIGNED,當然能使用TINYINT、SMALLINT、MEDIUM_INT更好。

  使用枚舉或者整數代替字符串類型

  盡量使用TIMESTAMP而非DATATIME

  單表不要有太多字段,建議在20以內

  用整形來存IP

索引:

  索引並不是越多越好,要根據查詢有針對性的創建,考慮在WHERE和ORDER BY命令上涉及的列建立索引,可根據EXPLAIN來查看是否用了索引還是全表掃描

  應盡量避免在WHERE子句中對字段進行NULL值判斷,否則將導致引擎放棄使用索引而進行全表掃描

  值分布很稀少的字段不適合建立索引,例如:性別

  字符字段只建前綴索引

  字符字段最好不要做主鍵

  不用外鍵,由程序保證約束

  盡量不用UNIQUE,由程序保證約束

  使用多列索引時注意順序和查詢條件保持一致,同時刪除不必要的單列索引

合適的數據類型:

  使用可存下數據的最小的數據類型

  使用簡單的數據類型

  使用合理的字段屬性長度,固定長度的表會更快

  盡可能使用not  null定義字段

  盡量少用text,非用不可最好分表

選擇合適的索引列:

  查詢頻繁的列,在where、group by、order by、on從句中出現的列

  where條件中<、<=、=、>、>=、between、in 以及 like 字符串+通配符(%)出現的列

  長度小的列,索引字段越小越好,因為數據庫的存儲單位是頁,一頁中能存下的數據越多越好

  離散度大的列,放在聯合索引前面。查看離散度,通過統計不同的列值來實現,count越大,離散程度越高

  

單庫的性能優化:

SQL的優化:

  使用limit對查詢結果的記錄進行限定

  避免select *, 將需要查找的字段列出來

  使用連接( join ) 來代替子查詢

  拆分大的delete 或 insert 語句

  可通過開啟慢查詢日志來找出較慢的SQL

  不做列運算,select  id  where  age + 1 = 10,任何對列的操作都將導致表掃描,它包括數據庫教程函數、計算表達式等等,查詢時要盡可能將操作移至等號右邊。

  sql語句盡可能簡單,一條sql只能在一個cpu運算,大語句拆成小語句,減少鎖的時間,一條大的sql可以堵死整個庫

  OR改寫成IN:OR的效率是N級別,IN的效率是log(n) 級別,in的個數建議控制在200以內

  不用函數和觸發器,在應用程序實現

  避免%xxx式查詢

  少用JOIN

  使用同類型進行比較,比如用 ‘123’ 和 ‘123’ 比,123 和 123 比

  盡量避免在WHERE字句中使用 != 或者 <> 操作符,否則引擎將放棄使用索引而進行全表掃描

  對於連續數值,使用BETWEEN不用IN: select  id  from  t  where  num  between 1 and 5

  列表數據不要拿全表,要使用limit來分頁,每頁數量也不要太大

分區:

  分區是一種簡單的水平拆分,用戶需要在建表的時候加上分區參數,對應用是透明的無需修改代碼

  對用戶來說,分區表是一個獨立的邏輯表,但是底層由多個物理子表組成,實現分區的代碼實際上是通過對一組底層表的對象封裝,但對SQL層來說是一個完全封裝底層的黑盒子。mysql實現分區的方式也意味着索引也是按照分區的子表定義,沒有全局索引

  用戶的SQL語句是需要針對分區表做優化,SQL條件中要帶上分區條件的列,從而使查詢定位到少量的分區上,否則就會掃描全部分區,可以通過EXPLAIN  PARTITIONS 來查看某條SQL語句會落在哪些分區上,從而進行SQL優化

分區的好處:

  可以讓單表存儲更多的數據

  分區表的數據更容易維護,可以通過清除整個分區批量刪除大量數據,也可以增加新的分區來支持新插入的數據。另外還可以對一個獨立的分區進行優化、檢查、修復等操作

  部分查詢能夠從查詢條件上確定只落在少數分區上,速度會很快

  分區表的數據還可以分布在不同的物理設備上,從而高效利用硬件設備

  可以使用分區表來避免某些特殊瓶頸,例如InnoDB單個索引的互斥訪問、ext3文件系統的inode競爭

  可以備份和恢復單個分區

分區的限制和缺點:

  一個表只能有1024個分區

  如果分區字段中有主鍵或者唯一索引的列,那么所有主鍵列和唯一索引列都必須包含進來

  分區表無法使用外鍵約束

  NULL值會使分區過濾無效

  所有分區必須使用相同的存儲引擎

分區的類型:

  RANGE分區:基於屬於一個給定連續區間的列值,把多行分配給分區

  LIST分區:類似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇

  HASH分區:基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算,這個函數可以包含Mysql中有效的、產生非負整數值的任何表達式

  KEY分區:類似於按HASH分區,區別在於KEY分區只支持計算一列或者多列,且Mysql服務器提供其自身的哈希函數,必須有一列或者多列包含整數值

 

按上述的優化方案優化后,還是查詢卡死,則可以考慮分表了,把一次查詢分成多次查詢,然后把結果組合返回給用戶。

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM