本文目錄一覽:
輕鬆優化MySQL-之索引優化2 附贈送優化口訣
索引是在存儲引擎中實現的,也就是說不同的存儲引擎,會使用不同的索引。MyISAM和InnoDB存儲引擎:只支持BTREE索引,也就是說默認使用BTREE,不能夠更換,MySQL5.7中InnoDB可以支持HASH索引;MEMORY/HEAP存儲引擎:支持HASH和BTREE索引。索引可劃分為單列索引(其中包括普通索引、唯一索引、主鍵索引)、組合索引、全文索引、空間索引,其中單列索引是一個索引只包含單個列,但一個表中可以有多個單列索引。
MySQL中基本索引類型,沒有什麼限制,允許在定義索引的列中插入重複值和空值,純粹為了查詢數據更快一點。
索引列中的值必須是唯一的,但是允許為空值,
是一種特殊的唯一索引,不允許有空值。
在表中的多個欄位組合上創建的索引,只有在查詢條件中使用了這些欄位的左邊欄位時,索引才會被使用,使用組合索引時遵循最左前綴集合。
由id、name和age3個欄位構成的索引,索引行中就按id/name/age的順序存放,索引可以索引下面欄位組合(id,name,age)、(id,name)或者(id)。如果要查詢的欄位不構成索引最左面的前綴,那麼就不會是用索引,比如,age或者(name,age)組合就不會使用索引查詢
全文索引,只有在MyISAM引擎上才能使用,只能在CHAR,VARCHAR,TEXT類型欄位上使用全文索引。全文索引就是在一堆文字中,通過其中的某個關鍵字等,就能找到該欄位所屬的記錄行,比如有”你是個大牛,神人 …” 通過大牛,可能就可以找到該條記錄。這裡說的是可能,因為全文索引的使用涉及了很多細節,我們只需要知道這個大概意思。
只有在MyISAM引擎上才能使用,空間索引是對空間數據類型的欄位建立的索引,MySQL中的空間數據類型有四種,GEOMETRY、POINT、LINESTRING、POLYGON。
在創建空間索引時,使用SPATIAL關鍵字。
創建空間索引的列,必須將其聲明為NOT NULL。。
SPATIAL INDEX spatIdx(g)
全值匹配我最愛,最左前綴要遵守;
帶頭大哥不能死,中間兄弟不能斷;
索引列上少計算,範圍之後全失效;
Like百分寫最右,覆蓋索引不寫星;
不等空值還有or,索引失效要少用;
VAR引號不可丟,SQL高級也不難!
參考: u;/u
參考: u;/u
如果索引包含滿足查詢的所有數據,就稱為覆蓋索引。覆蓋索引是一種非常強大的工具,能大大提高查詢性能。只需要讀取索引而不用讀取數據有以下一些優點:
(1) 索引項通常比記錄要小,所以MySQL訪問更少的數據;
(2) 索引都按值的大小順序存儲,相對於隨機訪問記錄,需要更少的I/O;
(3) 大多數據引擎能更好的緩存索引。比如MyISAM只緩存索引。
(4) 覆蓋索引對於InnoDB表尤其有用,因為InnoDB使用聚集索引組織數據,如果二級索引中包含查詢所需的數據,就不再需要在聚集索引中查找了。
覆蓋索引不能是任何索引,只有B-TREE索引存儲相應的值。而且不同的存儲引擎實現覆蓋索引的方式都不同,並不是所有存儲引擎都支持覆蓋索引(Memory和Falcon就不支持)。
對於索引覆蓋查詢(index-covered query),使用EXPLAIN時,可以在Extra一列中看到「Using index」。
產品中有一張圖片表,數據量將近100萬條,有一條相關的查詢語句,由於執行頻次較高,想針對此語句進行優化。表結構很簡單,主要欄位:
user_id 用戶ID
picname 圖片名稱
smallimg 小圖名稱
一個用戶會有多條圖片記錄,現在有一個根據user_id建立的索引:uid,查詢語句也很簡單。取得某用戶的圖片集合
執行查詢語句(為了查看真實執行時間,強制不使用緩存)
執行了10次,平均耗時在40ms左右。使用explain進行分析
使用了user_id的索引,並且是const常數查找,表示性能已經很好了
因為這個語句太簡單,sql本身沒有什麼優化空間,就考慮了索引。修改索引結構,建立一個(user_id,picname,smallimg)的聯合索引:uid_pic。重新執行10次,平均耗時降到了30ms左右。使用explain進行分析
看到使用的索引變成了剛剛建立的聯合索引,並且Extra部分顯示使用了’Using Index’
‘Using Index’的意思是「覆蓋索引」,它是使上面sql性能提升的關鍵。一個包含查詢所需欄位的索引稱為「覆蓋索引」,MySQL只需要通過索引就可以返回查詢所需要的數據,而不必在查到索引之後進行回表操作,減少IO,提高了效率。
例如上面的sql,查詢條件是user_id,可以使用聯合索引,要查詢的欄位是picname smallimg,這兩個欄位也在聯合索引中,這就實現了「覆蓋索引」,可以根據這個聯合索引一次性完成查詢工作,所以提升了性能
InnoDB存儲引擎由於實現了行級鎖定,雖然在鎖定機制的實現方面帶來的性能損耗可能比表級鎖定要更高一些,但是在整體並發處理能力方面是要遠遠優於MyISAM的表級鎖定的。當系統並發量較高的時候,InnoDB的整體性能和MyISAM相比就會有比較明顯的優勢了。但是當我們使用不當的時候,可能會讓InnoDB的整體性能表現不僅不比MyISAM高,甚至可能會更差。
建議:
(1)儘可能讓所有的數據檢索都通過索引來完成,從而避免InnoDB因為無法通過索引鍵加鎖而升級為表級鎖定
(2)合理設計索引,讓InnoDB在索引鍵上面加鎖的時候儘可能準確,儘可能地縮小鎖定範圍,避免造成不必要的鎖定而影響其他Query的執行
(3)儘可能減少基於範圍的數據檢索過濾條件,避免因為間隙鎖帶來的負面影響而鎖定了不該鎖定的記錄
(4)盡量控制事務的大小,減少鎖定的資源量和鎖定時間長度
(5)在業務環境允許的情況下,盡量使用較低級別的事務隔離,以減少MySQL因為實現事務隔離級別所帶來的附加成本。
優化MYSQL資料庫的方法
在開始演示之前,我們先介紹下兩個概念。
概念一,數據的可選擇性基數,也就是常說的cardinality值。
查詢優化器在生成各種執行計劃之前,得先從統計信息中取得相關數據,這樣才能估算每步操作所涉及到的記錄數,而這個相關數據就是cardinality。簡單來說,就是每個值在每個欄位中的唯一值分布狀態。
比如表t1有100行記錄,其中一列為f1。f1中唯一值的個數可以是100個,也可以是1個,當然也可以是1到100之間的任何一個數字。這裡唯一值越的多少,就是這個列的可選擇基數。
那看到這裡我們就明白了,為什麼要在基數高的欄位上建立索引,而基數低的的欄位建立索引反而沒有全表掃描來的快。當然這個只是一方面,至於更深入的探討就不在我這篇探討的範圍了。
概念二,關於HINT的使用。
這裡我來說下HINT是什麼,在什麼時候用。
HINT簡單來說就是在某些特定的場景下人工協助MySQL優化器的工作,使她生成最優的執行計劃。一般來說,優化器的執行計劃都是最優化的,不過在某些特定場景下,執行計劃可能不是最優化。
比如:表t1經過大量的頻繁更新操作,(UPDATE,DELETE,INSERT),cardinality已經很不準確了,這時候剛好執行了一條SQL,那麼有可能這條SQL的執行計劃就不是最優的。為什麼說有可能呢?
來看下具體演示
譬如,以下兩條SQL,
A:
select * from t1 where f1 = 20;
B:
select * from t1 where f1 = 30;
如果f1的值剛好頻繁更新的值為30,並且沒有達到MySQL自動更新cardinality值的臨界值或者說用戶設置了手動更新又或者用戶減少了sample page等等,那麼對這兩條語句來說,可能不準確的就是B了。
這裡順帶說下,MySQL提供了自動更新和手動更新表cardinality值的方法,因篇幅有限,需要的可以查閱手冊。
那回到正題上,MySQL 8.0 帶來了幾個HINT,我今天就舉個index_merge的例子。
示例表結構:
mysql desc t1;+————+————–+——+—–+———+—————-+| Field | Type | Null | Key | Default | Extra |+————+————–+——+—–+———+—————-+| id | int(11) | NO | PRI | NULL | auto_increment || rank1 | int(11) | YES | MUL | NULL | || rank2 | int(11) | YES | MUL | NULL | || log_time | datetime | YES | MUL | NULL | || prefix_uid | varchar(100) | YES | | NULL | || desc1 | text | YES | | NULL | || rank3 | int(11) | YES | MUL | NULL | |+————+————–+——+—–+———+—————-+7 rows in set (0.00 sec)
表記錄數:
mysql select count(*) from t1;+———-+| count(*) |+———-+| 32768 |+———-+1 row in set (0.01 sec)
這裡我們兩條經典的SQL:
SQL C:
select * from t1 where rank1 = 1 or rank2 = 2 or rank3 = 2;
SQL D:
select * from t1 where rank1 =100 and rank2 =100 and rank3 =100;
表t1實際上在rank1,rank2,rank3三列上分別有一個二級索引。
那我們來看SQL C的查詢計劃。
顯然,沒有用到任何索引,掃描的行數為32034,cost為3243.65。
mysql explain format=json select * from t1 where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: { “query_block”: { “select_id”: 1, “cost_info”: { “query_cost”: “3243.65” }, “table”: { “table_name”: “t1”, “access_type”: “ALL”, “possible_keys”: [ “idx_rank1”, “idx_rank2”, “idx_rank3” ], “rows_examined_per_scan”: 32034, “rows_produced_per_join”: 115, “filtered”: “0.36”, “cost_info”: { “read_cost”: “3232.07”, “eval_cost”: “11.58”, “prefix_cost”: “3243.65”, “data_read_per_join”: “49K” }, “used_columns”: [ “id”, “rank1”, “rank2”, “log_time”, “prefix_uid”, “desc1”, “rank3” ], “attached_condition”: “((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))” } }}1 row in set, 1 warning (0.00 sec)
我們加上hint給相同的查詢,再次看看查詢計劃。
這個時候用到了index_merge,union了三個列。掃描的行數為1103,cost為441.09,明顯比之前的快了好幾倍。
mysql explain format=json select /*+ index_merge(t1) */ * from t1 where rank1 =1 or rank2 = 2 or rank3 = 2\G*************************** 1. row ***************************EXPLAIN: { “query_block”: { “select_id”: 1, “cost_info”: { “query_cost”: “441.09” }, “table”: { “table_name”: “t1”, “access_type”: “index_merge”, “possible_keys”: [ “idx_rank1”, “idx_rank2”, “idx_rank3” ], “key”: “union(idx_rank1,idx_rank2,idx_rank3)”, “key_length”: “5,5,5”, “rows_examined_per_scan”: 1103, “rows_produced_per_join”: 1103, “filtered”: “100.00”, “cost_info”: { “read_cost”: “330.79”, “eval_cost”: “110.30”, “prefix_cost”: “441.09”, “data_read_per_join”: “473K” }, “used_columns”: [ “id”, “rank1”, “rank2”, “log_time”, “prefix_uid”, “desc1”, “rank3” ], “attached_condition”: “((`ytt`.`t1`.`rank1` = 1) or (`ytt`.`t1`.`rank2` = 2) or (`ytt`.`t1`.`rank3` = 2))” } }}1 row in set, 1 warning (0.00 sec)
我們再看下SQL D的計劃:
不加HINT,
mysql explain format=json select * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: { “query_block”: { “select_id”: 1, “cost_info”: { “query_cost”: “534.34” }, “table”: { “table_name”: “t1”, “access_type”: “ref”, “possible_keys”: [ “idx_rank1”, “idx_rank2”, “idx_rank3” ], “key”: “idx_rank1”, “used_key_parts”: [ “rank1” ], “key_length”: “5”, “ref”: [ “const” ], “rows_examined_per_scan”: 555, “rows_produced_per_join”: 0, “filtered”: “0.07”, “cost_info”: { “read_cost”: “478.84”, “eval_cost”: “0.04”, “prefix_cost”: “534.34”, “data_read_per_join”: “176” }, “used_columns”: [ “id”, “rank1”, “rank2”, “log_time”, “prefix_uid”, “desc1”, “rank3” ], “attached_condition”: “((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100))” } }}1 row in set, 1 warning (0.00 sec)
加了HINT,
mysql explain format=json select /*+ index_merge(t1)*/ * from t1 where rank1 =100 and rank2 =100 and rank3 =100\G*************************** 1. row ***************************EXPLAIN: { “query_block”: { “select_id”: 1, “cost_info”: { “query_cost”: “5.23” }, “table”: { “table_name”: “t1”, “access_type”: “index_merge”, “possible_keys”: [ “idx_rank1”, “idx_rank2”, “idx_rank3” ], “key”: “intersect(idx_rank1,idx_rank2,idx_rank3)”, “key_length”: “5,5,5”, “rows_examined_per_scan”: 1, “rows_produced_per_join”: 1, “filtered”: “100.00”, “cost_info”: { “read_cost”: “5.13”, “eval_cost”: “0.10”, “prefix_cost”: “5.23”, “data_read_per_join”: “440” }, “used_columns”: [ “id”, “rank1”, “rank2”, “log_time”, “prefix_uid”, “desc1”, “rank3” ], “attached_condition”: “((`ytt`.`t1`.`rank3` = 100) and (`ytt`.`t1`.`rank2` = 100) and (`ytt`.`t1`.`rank1` = 100))” } }}1 row in set, 1 warning (0.00 sec)
對比下以上兩個,加了HINT的比不加HINT的cost小了100倍。
總結下,就是說表的cardinality值影響這張的查詢計劃,如果這個值沒有正常更新的話,就需要手工加HINT了。相信MySQL未來的版本會帶來更多的HINT。
超詳細MySQL資料庫優化
資料庫優化一方面是找出系統的瓶頸,提高MySQL資料庫的整體性能,而另一方面需要合理的結構設計和參數調整,以提高用戶的相應速度,同時還要儘可能的節約系統資源,以便讓系統提供更大的負荷.
1. 優化一覽圖
2. 優化
筆者將優化分為了兩大類,軟優化和硬優化,軟優化一般是操作資料庫即可,而硬優化則是操作伺服器硬體及參數設置.
2.1 軟優化
2.1.1 查詢語句優化
1.首先我們可以用EXPLAIN或DESCRIBE(簡寫:DESC)命令分析一條查詢語句的執行信息.
2.例:
顯示:
其中會顯示索引和查詢數據讀取數據條數等信息.
2.1.2 優化子查詢
在MySQL中,盡量使用JOIN來代替子查詢.因為子查詢需要嵌套查詢,嵌套查詢時會建立一張臨時表,臨時表的建立和刪除都會有較大的系統開銷,而連接查詢不會創建臨時表,因此效率比嵌套子查詢高.
2.1.3 使用索引
索引是提高資料庫查詢速度最重要的方法之一,關於索引可以參高筆者MySQL資料庫索引一文,介紹比較詳細,此處記錄使用索引的三大注意事項:
2.1.4 分解表
對於欄位較多的表,如果某些欄位使用頻率較低,此時應當,將其分離出來從而形成新的表,
2.1.5 中間表
對於將大量連接查詢的表可以創建中間表,從而減少在查詢時造成的連接耗時.
2.1.6 增加冗餘欄位
類似於創建中間表,增加冗餘也是為了減少連接查詢.
2.1.7 分析表,,檢查表,優化表
分析表主要是分析表中關鍵字的分布,檢查表主要是檢查表中是否存在錯誤,優化表主要是消除刪除或更新造成的表空間浪費.
1. 分析表: 使用 ANALYZE 關鍵字,如ANALYZE TABLE user;
2. 檢查表: 使用 CHECK關鍵字,如CHECK TABLE user [option]
option 只對MyISAM有效,共五個參數值:
3. 優化表:使用OPTIMIZE關鍵字,如OPTIMIZE [LOCAL|NO_WRITE_TO_BINLOG] TABLE user;
LOCAL|NO_WRITE_TO_BINLOG都是表示不寫入日誌.,優化表只對VARCHAR,BLOB和TEXT有效,通過OPTIMIZE TABLE語句可以消除文件碎片,在執行過程中會加上只讀鎖.
2.2 硬優化
2.2.1 硬體三件套
1.配置多核心和頻率高的cpu,多核心可以執行多個線程.
2.配置大內存,提高內存,即可提高緩存區容量,因此能減少磁碟I/O時間,從而提高響應速度.
3.配置高速磁碟或合理分布磁碟:高速磁碟提高I/O,分布磁碟能提高並行操作的能力.
2.2.2 優化資料庫參數
優化資料庫參數可以提高資源利用率,從而提高MySQL伺服器性能.MySQL服務的配置參數都在my.cnf或my.ini,下面列出性能影響較大的幾個參數.
2.2.3 分庫分表
因為資料庫壓力過大,首先一個問題就是高峰期系統性能可能會降低,因為資料庫負載過高對性能會有影響。另外一個,壓力過大把你的資料庫給搞掛了怎麼辦?所以此時你必須得對系統做分庫分表 + 讀寫分離,也就是把一個庫拆分為多個庫,部署在多個資料庫服務上,這時作為主庫承載寫入請求。然後每個主庫都掛載至少一個從庫,由從庫來承載讀請求。
2.2.4 緩存集群
如果用戶量越來越大,此時你可以不停的加機器,比如說系統層面不停加機器,就可以承載更高的並發請求。然後資料庫層面如果寫入並發越來越高,就擴容加資料庫伺服器,通過分庫分表是可以支持擴容機器的,如果資料庫層面的讀並發越來越高,就擴容加更多的從庫。但是這裡有一個很大的問題:資料庫其實本身不是用來承載高並發請求的,所以通常來說,資料庫單機每秒承載的並發就在幾千的數量級,而且資料庫使用的機器都是比較高配置,比較昂貴的機器,成本很高。如果你就是簡單的不停的加機器,其實是不對的。所以在高並發架構里通常都有緩存這個環節,緩存系統的設計就是為了承載高並發而生。所以單機承載的並發量都在每秒幾萬,甚至每秒數十萬,對高並發的承載能力比資料庫系統要高出一到兩個數量級。所以你完全可以根據系統的業務特性,對那種寫少讀多的請求,引入緩存集群。具體來說,就是在寫資料庫的時候同時寫一份數據到緩存集群里,然後用緩存集群來承載大部分的讀請求。這樣的話,通過緩存集群,就可以用更少的機器資源承載更高的並發。
一個完整而複雜的高並發系統架構中,一定會包含:各種複雜的自研基礎架構系統。各種精妙的架構設計.因此一篇小文頂多具有拋磚引玉的效果,但是資料庫優化的思想差不多就這些了.
MySQL資料庫性能優化之分區分表分庫
分表是分散資料庫壓力的好方法。
分表,最直白的意思,就是將一個表結構分為多個表,然後,可以再同一個庫里,也可以放到不同的庫。
當然,首先要知道什麼情況下,才需要分表。個人覺得單表記錄條數達到百萬到千萬級別時就要使用分表了。
分表的分類
**1、縱向分表**
將本來可以在同一個表的內容,人為劃分為多個表。(所謂的本來,是指按照關係型資料庫的第三範式要求,是應該在同一個表的。)
分表理由:根據數據的活躍度進行分離,(因為不同活躍的數據,處理方式是不同的)
案例:
對於一個博客系統,文章標題,作者,分類,創建時間等,是變化頻率慢,查詢次數多,而且最好有很好的實時性的數據,我們把它叫做冷數據。而博客的瀏覽量,回複數等,類似的統計信息,或者別的變化頻率比較高的數據,我們把它叫做活躍數據。所以,在進行資料庫結構設計的時候,就應該考慮分表,首先是縱向分表的處理。
這樣縱向分表後:
首先存儲引擎的使用不同,冷數據使用MyIsam 可以有更好的查詢數據。活躍數據,可以使用Innodb ,可以有更好的更新速度。
其次,對冷數據進行更多的從庫配置,因為更多的操作時查詢,這樣來加快查詢速度。對熱數據,可以相對有更多的主庫的橫向分表處理。
其實,對於一些特殊的活躍數據,也可以考慮使用memcache ,redis之類的緩存,等累計到一定量再去更新資料庫。或者mongodb 一類的nosql 資料庫,這裡只是舉例,就先不說這個。
**2、橫向分表**
字面意思,就可以看出來,是把大的表結構,橫向切割為同樣結構的不同表,如,用戶信息表,user_1,user_2等。表結構是完全一樣,但是,根據某些特定的規則來劃分的表,如根據用戶ID來取模劃分。
分表理由:根據數據量的規模來劃分,保證單表的容量不會太大,從而來保證單表的查詢等處理能力。
案例:同上面的例子,博客系統。當博客的量達到很大時候,就應該採取橫向分割來降低每個單表的壓力,來提升性能。例如博客的冷數據表,假如分為100個表,當同時有100萬個用戶在瀏覽時,如果是單表的話,會進行100萬次請求,而現在分表後,就可能是每個表進行1萬個數據的請求(因為,不可能絕對的平均,只是假設),這樣壓力就降低了很多很多。
延伸:為什麼要分表和分區?
日常開發中我們經常會遇到大表的情況,所謂的大表是指存儲了百萬級乃至千萬級條記錄的表。這樣的表過於龐大,導致資料庫在查詢和插入的時候耗時太長,性能低下,如果涉及聯合查詢的情況,性能會更加糟糕。分表和表分區的目的就是減少資料庫的負擔,提高資料庫的效率,通常點來講就是提高表的增刪改查效率。
什麼是分表?
分表是將一個大表按照一定的規則分解成多張具有獨立存儲空間的實體表,我們可以稱為子表,每個表都對應三個文件,MYD數據文件,.MYI索引文件,.frm表結構文件。這些子表可以分布在同一塊磁碟上,也可以在不同的機器上。app讀寫的時候根據事先定義好的規則得到對應的子表名,然後去操作它。
什麼是分區?
分區和分表相似,都是按照規則分解表。不同在於分表將大表分解為若干個獨立的實體表,而分區是將數據分段劃分在多個位置存放,可以是同一塊磁碟也可以在不同的機器。分區後,表面上還是一張表,但數據散列到多個位置了。app讀寫的時候操作的還是大表名字,db自動去組織分區的數據。
**MySQL分表和分區有什麼聯繫呢?**
1、都能提高mysql的性高,在高並髮狀態下都有一個良好的表現。
2、分表和分區不矛盾,可以相互配合的,對於那些大訪問量,並且表數據比較多的表,我們可以採取分表和分區結合的方式(如果merge這種分表方式,不能和分區配合的話,可以用其他的分表試),訪問量不大,但是表數據很多的表,我們可以採取分區的方式等。
3、分表技術是比較麻煩的,需要手動去創建子表,app服務端讀寫時候需要計運算元表名。採用merge好一些,但也要創建子表和配置子表間的union關係。
4、表分區相對於分表,操作方便,不需要創建子表。
我們知道對於大型的互聯網應用,資料庫單表的數據量可能達到千萬甚至上億級別,同時面臨這高並發的壓力。Master-Slave結構只能對資料庫的讀能力進行擴展,寫操作還是集中在Master中,Master並不能無限制的掛接Slave庫,如果需要對資料庫的吞吐能力進行進一步的擴展,可以考慮採用分庫分表的策略。
**1、分表**
在分表之前,首先要選中合適的分表策略(以哪個字典為分表欄位,需要將數據分為多少張表),使數據能夠均衡的分布在多張表中,並且不影響正常的查詢。在企業級應用中,往往使用org_id(組織主鍵)做為分表欄位,在互聯網應用中往往是userid。在確定分表策略後,當數據進行存儲及查詢時,需要確定到哪張表裡去查找數據,
數據存放的數據表 = 分表欄位的內容 % 分表數量
**2、分庫**
分表能夠解決單表數據量過大帶來的查詢效率下降的問題,但是不能給資料庫的並發訪問帶來質的提升,面對高並發的寫訪問,當Master無法承擔高並發的寫入請求時,不管如何擴展Slave伺服器,都沒有意義了。我們通過對資料庫進行拆分,來提高資料庫的寫入能力,即所謂的分庫。分庫採用對關鍵字取模的方式,對資料庫進行路由。
數據存放的資料庫=分庫欄位的內容%資料庫的數量
**3、即分表又分庫**
資料庫分表可以解決單表海量數據的查詢性能問題,分庫可以解決單台資料庫的並發訪問壓力問題。
當資料庫同時面臨海量數據存儲和高並發訪問的時候,需要同時採取分表和分庫策略。一般分表分庫策略如下:
中間變數 = 關鍵字%(資料庫數量*單庫數據表數量)
庫 = 取整(中間變數/單庫數據表數量)
表 = (中間變數%單庫數據表數量)
實例:
1、分庫分表
很明顯,一個主表(也就是很重要的表,例如用戶表)無限制的增長勢必嚴重影響性能,分庫與分表是一個很不錯的解決途徑,也就是性能優化途徑,現在的案例是我們有一個1000多萬條記錄的用戶表members,查詢起來非常之慢,同事的做法是將其散列到100個表中,分別從members0到members99,然後根據mid分發記錄到這些表中,牛逼的代碼大概是這樣子:
複製代碼 代碼如下:
?php
for($i=0;$i 100; $i++ ){
//echo “CREATE TABLE db2.members{$i} LIKE db1.members
“;
echo “INSERT INTO members{$i} SELECT * FROM members WHERE mid%100={$i}
“;
}
?
2、不停機修改mysql表結構
同樣還是members表,前期設計的表結構不盡合理,隨著資料庫不斷運行,其冗餘數據也是增長巨大,同事使用了下面的方法來處理:
先創建一個臨時表:
/*創建臨時表*/
CREATE TABLE members_tmp LIKE members
然後修改members_tmp的表結構為新結構,接著使用上面那個for循環來導出數據,因為1000萬的數據一次性導出是不對的,mid是主鍵,一個區間一個區間的導,基本是一次導出5萬條吧,這裡略去了
接著重命名將新表替換上去:
/*這是個頗為經典的語句哈*/
RENAME TABLE members TO members_bak,members_tmp TO members;
就是這樣,基本可以做到無損失,無需停機更新表結構,但實際上RENAME期間表是被鎖死的,所以選擇在線少的時候操作是一個技巧。經過這個操作,使得原先8G多的表,一下子變成了2G多。
原創文章,作者:TFMU,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/140362.html