天天看點

【轉載】一次 MySQL 千萬級大表的優化過程

方案概述

  • 方案一:優化現有MySQL資料庫。優點:不影響現有業務,源程式不需要修改代碼,成本最低。缺點:有優化瓶頸,資料量過億就玩完了。
  • 方案二:更新資料庫類型,換一種100%相容MySQL的資料庫。優點:不影響現有業務,源程式不需要修改代碼,你幾乎不需要做任何操作就能提升資料庫性能,缺點:多花錢。
  • 方案三:一步到位,大資料解決方案,更換newSQL/noSQL資料庫。優點:沒有資料容量瓶頸,缺點:需要修改源程式代碼,影響業務,總成本最高。

優化現有MySQL資料庫

資料庫設計

  • 表字段避免null值出現,null值很難查詢優化且占用額外的索引空間,推薦預設數字0代替null。
  • 盡量使用INT而非BIGINT,如果非負則加上UNSIGNED(這樣數值容量會擴大一倍),當然能使用TINYINT、SMALLINT、MEDIUM_INT更好。
  • 使用枚舉或整數代替字元串類型。
  • 盡量使用TIMESTAMP而非DATETIME。
  • 單表不要有太多字段,建議在20以内。
  • 用整型來存IP。

索引設計

  • 索引并不是越多越好,要根據查詢有針對性的建立,考慮在WHERE和ORDER BY指令上涉及的列建立索引,可根據EXPLAIN來檢視是否用了索引還是全表掃描。
  • 應盡量避免在WHERE子句中對字段進行NULL值判斷,否則将導緻引擎放棄使用索引而進行全表掃描。
  • 值分布很稀少的字段不适合建索引,例如"性别"這種隻有兩三個值的字段。
  • 字元字段隻建字首索引。
  • 字元字段最好不要做主鍵。
  • 不用外鍵,由程式保證限制。
  • 盡量不用UNIQUE,由程式保證限制。
  • 使用多列索引時注意順序和查詢條件保持一緻,同時删除不必要的單列索引。
  • 使用可存下資料的最小的資料類型,整型 < date,time < char,varchar < blob*
  • 使用簡單的資料類型,整型比字元處理開銷更小,因為字元串的比較更複雜。如,int類型存儲時間類型,bigint類型轉ip函數。
  • 使用合理的字段屬性長度,固定長度的表會更快。使用enum、char而不是varchar。
  • 盡可能使用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來分頁,每頁數量也不要太大。

分區

  • 可以讓單表存儲更多的資料。
  • 分區表的資料更容易維護,可以通過清楚整個分區批量删除大量資料,也可以增加新的分區來支援新插入的資料。另外,還可以對一個獨立分區進行優化、檢查、修複等操作。
  • 部分查詢能夠從查詢條件确定隻落在少數分區上,速度會很快。
  • 分區表的資料還可以分布在不同的實體裝置上,進而搞笑利用多個硬體裝置。
  • 可以使用分區表賴避免某些特殊瓶頸,例如InnoDB單個索引的互斥通路、ext3檔案系統的inode鎖競争。
  • 可以備份和恢複單個分區。
  • 一個表最多隻能有1024個分區。
  • 如果分區字段中有主鍵或者唯一索引的列,那麼所有主鍵列和唯一索引列都必須包含進來。
  • 分區表無法使用外鍵限制。
  • NULL值會使分區過濾無效。
  • 所有分區必須使用相同的存儲引擎。

分表

  • 分表就是把一張大表,按照如上過程都優化了,還是查詢卡死,那就把這個表分成多張表,把一次查詢分成多次查詢,然後把結果組合傳回給使用者。
  • 分表分為垂直拆分和水準拆分,通常以某個字段做拆分項。比如以id字段拆分為100張表:表名為 tableName_id%100。
  • 但:分表需要修改源程式代碼,會給開發帶來大量工作,極大的增加了開發成本,故:隻适合在開發初期就考慮到了大量資料存在,做好了分表處理,不适合應用上線了再做修改,成本太高!!!而且選擇這個方案,都不如選擇我提供的第二第三個方案的成本低!故不建議采用。

分庫

  • 把一個資料庫分成多個,建議做個讀寫分離就行了,真正的做分庫也會帶來大量的開發成本,得不償失!不推薦使用。

更新資料庫

  • 開源資料庫會帶來大量的運維成本且其工業品質和MySQL尚有差距,有很多坑要踩,如果你公司要求必須自建資料庫,那麼選擇該類型産品。如tiDB pingcap/tidb,Cubrid Open Source Database With Enterprise Features。
  • 阿裡雲POLARDB,POLARDB 是阿裡雲自研的下一代關系型分布式雲原生資料庫,100%相容MySQL,存儲容量最高可達 100T,性能最高提升至 MySQL 的 6 倍。POLARDB 既融合了商業資料庫穩定、可靠、高性能的特征,又具有開源資料庫簡單、可擴充、持續疊代的優勢,而成本隻需商用資料庫的 1/10。
  • 阿裡雲OcenanBase,淘寶使用的,扛得住雙十一,性能卓著,但是在公測中,我無法嘗試,但值得期待。
  • 阿裡雲HybridDB for MySQL (原PetaData),雲資料庫HybridDB for MySQL (原名PetaData)是同時支援海量資料線上事務(OLTP)和線上分析(OLAP)的HTAP(Hybrid Transaction/Analytical Processing) 關系型資料庫
  • 騰訊雲DCDB,DCDB又名TDSQL,一種相容MySQL協定和文法,支援自動水準拆分的高性能分布式資料庫——即業務顯示為完整的邏輯表,資料卻均勻的拆分到多個分片中;每個分片預設采用主備架構,提供災備、恢複、監控、不停機擴容等全套解決方案,适用于TB或PB級的海量資料場景。

換大資料引擎

  • hadoop家族。hbase/hive怼上就是了。但是有很高的運維成本,一般公司是玩不起的,沒十萬投入是不會有很好的産出的!
  • 我選擇了阿裡雲的MaxCompute配合DataWorks,使用超級舒服,按量付費,成本極低。
  • MaxCompute可以了解為開源的Hive,提供SQL/mapreduce/ai算法/python腳本/shell腳本等方式操作資料,資料以表格的形式展現,以分布式方式存儲,采用定時任務和批處理的方式處理資料。DataWorks提供了一種工作流的方式管理你的資料處理任務和排程監控。
  • 當然你也可以選擇阿裡雲hbase等其他産品,我這裡主要是離線處理,故選擇MaxCompute,基本都是圖形界面操作,大概寫了300行SQL,費用不超過100塊錢就解決了資料處理問題。

原作者:趙客缦胡纓v吳鈎霜雪明

來源:

https://www.jianshu.com/p/336f682e4b91

更多關于大資料計算、雲數倉技術交流,可掃碼加入 “MaxCompute開發者社群” 釘釘群

【轉載】一次 MySQL 千萬級大表的優化過程