1. 程式人生 > >MySQL 大資料量表優化方案

MySQL 大資料量表優化方案

單表優化

  • 除非單表資料未來會一直不斷上漲(例如網路爬蟲),否則不要一開始就考慮拆分,拆分會帶來邏輯、部署、運維的各種複雜度
  • 一般以整型值為主的表在 千萬級以下,字串為主的表在 五百萬以下是沒有太大問題的。而事實上很多時候 MySQL 單表的效能依然有不少優化空間,甚至能正常支撐千萬級以上的資料量。

字 段

  • 儘量使用 tinyint、 smallint、 mediumint 作為整數型別而非 int

  • 建議 varchar 的長度只分配真正需要的空間

  • 使用列舉或整數代替字串型別

  • 儘量使用 TIMESTAMP而非 DATETIME

  • 單表不要有太多欄位,建議在20以內

  • 避免使用NULL欄位,很難查詢優化且佔用額外索引空間

索 引

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

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

  • 值分佈很稀少的欄位不適合建索引,例如 "性別" 這種只有兩三個值的欄位

  • 字元欄位只建字首索引

  • 字元欄位最好不要做主鍵

  • 儘量不用外來鍵,由程式保證約束

  • 儘量不用 UNIQUE,由程式保證約束

查詢 SQL

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

  • 不做列運算: SELECT id WHERE age+1=10,任何對列的操作都將導致表掃描,它包括資料庫教程函式、計算表示式等等,查詢時要儘可能將操作移至等號右邊

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

  • 不用 SELECT *

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

  • 不用函式和觸發器,在應用程式實現

  • 避免 %xxx 式查詢

  • 少用 JOIN

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

  • 對於連續數值,使用 BETWEEN 不用 IN, SELECT id FROM t WHERE num BETWEEN 1 AND 5

  • 列表資料不要拿全表,要使用 LIMIT來分頁,每頁數量也不要太大

引 擎

升級硬體

  • 這個不多說了,根據 MySQL 是 CPU 密集型還是I/O密集型,通過提升 CPU 和記憶體、使用 SSD,都能顯著提升MySQL效能

讀寫分離

  • 讀寫分離也是目前常用的優化方式,從庫讀主庫寫
  • 一般不要採用雙主或多主引入很多複雜性,儘量採用文中的其他方案來提高效能。同時目前很多拆分的解決方案同時也兼顧考慮了讀寫分離

緩 存

  • 快取可以發生在以下這些層次:
  1. MySQL內部:做內部引數調優

  2. 資料訪問層:比如 MyBatis 針對 SQL 語句做快取,而 Hibernate 可以精確到單個記錄,這裡快取的物件主要是持久化物件 PersistenceObject

  3. 應用服務層:這裡可以通過程式設計手段對快取做到更精準的控制和更多的實現策略,這裡快取的物件是資料傳輸物件 DataTransferObject

  4. Web層:針對web頁面做快取

  5. 瀏覽器客戶端:使用者端的快取

  • 可以根據實際情況在一個層次或多個層次結合加入快取。這裡重點介紹下服務層的快取實現,目前主要有兩種方式:
  1. 直寫式(Write Through):在資料寫入資料庫後,同時更新快取(如 Redis),維持資料庫與快取的一致性。這也是當前大多數應用快取框架如 Spring Cache 的工作方式。這種實現非常簡單,同步好,但效率一般。

  2. 回寫式(Write Back):當有資料要寫入資料庫時,只會更新快取,然後非同步批量的將快取資料同步到資料庫上。這種實現比較複雜,需要較多的應用邏輯,同時可能會產生資料庫與快取的不同步,但效率非常高。

表分割槽

  • MySQL在5.1版引入的分割槽是一種簡單的水平拆分,使用者需要在建表的時候加上分割槽引數,對應用是透明的無需修改程式碼
  • 對使用者來說,分割槽表是一個獨立的邏輯表,但是底層由多個物理子表組成,實現分割槽的程式碼實際上是通過對一組底層表的物件封裝,但對SQL層來說是一個完全封裝底層的黑盒子。
  • MySQL實現分割槽的方式也意味著索引也是按照分割槽的子表定義,沒有全域性索引。

  • 使用者的SQL語句是需要針對分割槽表做優化,SQL條件中要帶上分割槽條件的列,從而使查詢定位到少量的分割槽上,否則就會掃描全部分割槽,可以通過 EXPLAIN PARTITIONS來檢視某條SQL語句會落在那些分割槽上,從而進行SQL優化,如下圖5條記錄落在兩個分割槽上:
    mysql> explain partitions select count(1) from user_partition where id in (1,2,3,4,5);

    +----+-------------+----------------+------------+-------+---------------+---------+---------+------+------+--------------------------+

    | id | select_type | table          | partitions | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |

    +----+-------------+----------------+------------+-------+---------------+---------+---------+------+------+--------------------------+

    |  1 | SIMPLE      | user_partition | p1,p4      | range | PRIMARY       | PRIMARY | 8       | NULL |    5 | Using where; Using index |

    +----+-------------+----------------+------------+-------+---------------+---------+---------+------+------+--------------------------+

    1 row in set (0.00 sec)

分割槽的優點

  • 可以讓單表儲存更多的資料

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

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

  • 分割槽表的資料還可以分佈在不同的物理裝置上,從而高效利用多個硬體裝置

  • 可以使用分割槽表來避免某些特殊瓶頸,例如 InnoDB 單個索引的互斥訪問、ext3 檔案系統的 InoDB 鎖競爭

  • 可以備份和恢復單個分割槽

分割槽的限制

  • 一個表最多隻能有1024個分割槽

  • 如果分割槽欄位中有主鍵或者唯一索引的列,那麼所有主鍵列和唯一索引列都必須包含進來

  • 分割槽表無法使用外來鍵約束

  • NULL值會使分割槽過濾無效

  • 所有分割槽必須使用相同的儲存引擎

分割槽的型別

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

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

  • hash 分割槽:基於使用者定義的表示式的返回值來進行選擇的分割槽,該表示式使用將要插入到表中的這些行的列值進行計算。這個函式可以包含MySQL中有效的、產生非負整數值的任何表示式

  • key 分割槽:類似於按 HASH 分割槽,區別在於 KEY 分割槽只支援計算一列或多列,且MySQL伺服器提供其自身的雜湊函式。必須有一列或多列包含整數值

垂直拆分

  • 垂直分庫是根據資料庫裡面的資料表的相關性進行拆分,比如:一個數據庫裡面既存在使用者資料,又存在訂單資料,那麼垂直拆分可以把使用者資料放到使用者庫、把訂單資料放到訂單庫。
  • 垂直分表是對資料表進行垂直拆分的一種方式,常見的是把一個多欄位的大表按常用欄位和非常用欄位進行拆分,每個表裡面的資料記錄數一般情況下是相同的,只是欄位不一樣,使用主鍵關聯。
  • 比如原始的使用者表是:

  • 垂直拆分後是:

優 點

  • 可以使得行資料變小,一個數據塊(Block)就能存放更多的資料,在查詢時就會減少I/O次數(每次查詢時讀取的Block 就少)

  • 可以達到最大化利用Cache的目的,具體在垂直拆分的時候可以將不常變的欄位放一起,將經常改變的放一起

  • 資料維護簡單

缺 點

  • 主鍵出現冗餘,需要管理冗餘列

  • 會引起表連線JOIN操作(增加CPU開銷)可以通過在業務伺服器上進行join來減少資料庫壓力

  • 依然存在單表資料量過大的問題(需要水平拆分)

  • 事務處理複雜

水平拆分

  • 水平拆分是通過某種策略將資料分片來儲存,分為庫內分表和分庫兩部分,每片資料會分散到不同的MySQL表或庫,達到分散式的效果,能夠支援非常大的資料量。前面的表分割槽本質上也是一種特殊的庫內分表。
  • 庫內分表,僅僅是單純的解決了單一表資料過大的問題,由於沒有把表的資料分佈到不同的機器上,因此對於減輕MySQL伺服器的壓力來說,並沒有太大的作用,大家還是競爭同一個物理機上的IO、CPU、網路,這個就要通過分庫來解決。
  • 前面垂直拆分的使用者表如果進行水平拆分,結果是:

  • 實際情況中往往會是垂直拆分和水平拆分的結合,即將 Users_A_MUsers_N_Z再拆成 UsersUserExtras,這樣一共四張表。

優 點

  • 不存在單庫大資料和高併發的效能瓶頸

  • 應用端改造較少

  • 提高了系統的穩定性和負載能力

缺點

  • 分片事務一致性難以解決

  • 跨節點 Join 效能差,邏輯複雜

  • 資料多次擴充套件難度跟維護量極大

相關推薦

MySQL 料量優化方案

單表優化 除非單表資料未來會一直不斷上漲(例如網路爬蟲),否則不要一開始就考慮拆分,拆分會帶來邏輯、部署、運維的各種複雜度 一般以整型值為主的表在 千萬級以下,字串為主的表在 五百萬以下是沒有太大問題的。而事實上很多時候 MySQL 單表的效能依然有不少優化空間,甚至能正

mysql料量優化

1 優化sql和索引2 增加快取如:redis3 主從複製或主主複製,讀寫分離4 利用mysql自帶分割槽表5 先做垂直拆分,將一個大系統分為多個小系統,也就是分散式6 水平切分,要選擇一個合理的sharding key,為了有好的查詢效率,表結構也要改動,做一定的冗餘,應用也要改,sql中儘量帶shardi

MySQL料量分頁查詢方法及其優化 ---方法1: 直接使用資料庫提供的SQL語句 ---語句樣式: MySQL中,可用如下方法: SELECT * FROM 名稱 LIMIT M,N ---適

測試實驗 1.   直接用limit start, count分頁語句, 也是我程式中用的方法: select * from product limit start, count 當起始頁較小時,查詢沒有效能問題,我們分別看下從10, 100, 1000, 10000開始分頁的執行時間(每頁取20條), 如

料量的查詢優化及索引使用

一、對於運算邏輯,儘可能將要統計的各專案整合在一個查詢語句中計算,而不是用分組條件或分專案呼叫多個查詢語句,而後在程式碼裡計算結果。 二、查詢語句的優化,諸如不用"select *"、多表關聯查詢時新增別名於查詢欄位上、避免使用in、not in關鍵字、非去除重複時用union all替換uni

MySQL料量分頁查詢方法及其優化 MySQL料量分頁查詢方法及其優化

MySQL大資料量分頁查詢方法及其優化   ---方法1: 直接使用資料庫提供的SQL語句---語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N ---適應場景: 適用於資料量較少的情況(元組百/千級) --

Mysql千萬級料量查詢優化

1.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t where num i

mysql 料量分頁優化

假設有一個千萬量級的表,取1到10條資料; select * from table limit 0,10; select * from table limit 1000,10; 這兩條語句查詢時間應該在毫秒級完成; select * from table limit

MySQL料量分頁查詢方法及其優化

方法1: 直接使用資料庫提供的SQL語句 語句樣式: MySQL中,可用如下方法: SELECT * FROM 表名稱 LIMIT M,N 適應場景: 適用於資料量較少的情況(元組百/千級) 原因/缺點: 全表掃描,速度會很慢 且 有的資料庫結果集返回不穩定(如某次返回

mysql 料量時 limit查詢優化

一般,我們在做分頁時,用的是語句如下:select * from table LIMIT 5,10; #返回第6-15行資料但是,如果資料量很大,比如>1000萬,則利用以上的查詢會非常慢,可以利用以下語句進行優化:Select * From table Where I

MySql 料量快速插入和語句優化

INSERT語句的速度 插入一個記錄需要的時間由下列因素組成,其中的數字表示大約比例:連線:(3) 傳送查詢給伺服器:(2) 分析查詢:(2) 插入記錄:(1x記錄大小) 插入索引:(1x索引) 關閉:(1) 這不考慮開啟表的初始開銷,每個併發執行的查詢開啟。

MySQL料量分頁SQL語句優化

分頁程式原理很簡單,這裡就不多說了,本篇文章主要說的是在資料表記錄量比較大的情況下,如何將分頁SQL做到更優化,讓MySQL執行的更快的方法。 一般的情況下,我們的分頁SQL語句是這樣的:

Oracle 料量查詢優化

前言:平常寫的SQL可能主要以實現查詢出結果為主,但如果資料量一大,就會突出SQL查詢語句優化的效能獨特之處.一般的資料庫設計都會建索引查詢,這樣較全盤掃描查詢的確快了不少.下面總結下SQL查詢語句的幾個優化效率的地方,經驗有限,難免有不足.    1.對查詢進行優化,應儘

通過索引,極大提高MySQL料量下的查詢效率

我在這裡測試了兩個表的左連線查詢,SQL語句是:select a.blog_id,a.blog_title,a.blog_thumb,a.blog_click,a.blog_addtime,a.blog_show,b.blog_category_name from `thin

java mysql料量批量插入與流式讀取分析

總結下這周幫助客戶解決報表生成操作的mysql 驅動的使用上的一些問題,與解決方案。由於生成報表邏輯要從資料庫讀取大量資料並在記憶體中加工處理後在 生成大量的彙總資料然後寫入到資料庫。基本流程是 讀取->處理->寫入。 1 讀取操作開始遇到的問題是當sql查詢資料量比較大時候基本讀不出來。開始

料量查詢優化

問題描述:涉及到大資料量,多迴圈查詢的時候,往往查詢的速度會變慢,影響系統的使用效能。該問題,在測試環境尚不明顯,因為測試環境的資料量畢竟是有限的。 但是,一旦將程式碼更新到線上的真實系統,因為資料量一下子增大,會造成資料查詢的緩慢,所造成的嚴重遲滯,就不能被忽略了。 業

MySQL料量快速分頁實現

以下分享一點我的經驗 一般剛開始學SQL語句的時候,會這樣寫 程式碼如下: SELECT * FROM table ORDER BY id LIMIT 1000, 10; 但在資料達到百萬級的時候,這樣寫會慢死 程式碼如下: SELECT * FROM tabl

.NET 料量併發解決方案

大併發大資料量請求一般會分為幾種情況:大量的使用者同時對系統的不同功能頁面進行查詢、更新操作大量的使用者同時對系統的同一個頁面,同一個表的大資料量進行查詢操作大量的使用者同時對系統的同一個頁面,同一個表進行更新操作第一類情況 :大量的使用者同時對系統的不同功能頁面進行查詢、更

Mysql料量儲存及訪問的設計討論-設計

轉載請註明來源:Mysql大資料量儲存及訪問的設計討論    一、引言   隨著網際網路應用的廣泛普及,海量資料的儲存和訪問成為了系統設計的瓶頸問題。對於一個大型的網際網路應用,每天幾十億的PV無疑對資料庫造成了相當高的負載。對於系統的穩定性和擴充套件性造成了極大的問題。通過

提高MYSQL料量查詢的速度

1.對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。 2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描,如:select id from t wher

Mysql料量問題與解決

今日格言:瞭解了為什麼,問題就解決了一半。 Mysql 單表適合的最大資料量是多少? 我們說 Mysql 單表適合儲存的最大資料量,自然不是說能夠儲存的最大資料量,如果是說能夠儲存的最大量,那麼,如果你使用自增 ID,最大就可以儲存 2^32 或 2^64 條記錄了,這是按自增 ID 的資料型別 int