1. 程式人生 > >MYSQL線上資料庫大表歸檔方法

MYSQL線上資料庫大表歸檔方法



前言

作為一個企業或者DBA,我們通常會有這種想法,資料是一個公司的核心命脈,應該需要永久儲存,很多時候DBA和開發溝通的時候,開發人員也會這麼告訴我們,這份資料非常重要,資料需要永久儲存。然而,如果將資料庫的資料永久儲存,那麼遲早有一天,你會擁有一個非常大的資料庫。作為一個DBA,通常為了業務對資料庫的操作效能考慮和儲存容量的考慮。我們會建議對資料庫裡大表進行資料歸檔,例如將使用的高頻資料保留在當前表,對低頻資料保留在歸檔表中。當然有些公司會將資料抽取到Hadoop、Hbase進行歸檔和離線分析,或者使用infobright作為歸檔引擎,這裡不們不做具體深入分析。本文我們只從DBA運維人員的角度,是用MySQL現有技術來幫大家分析如何對大表進行歸檔,以提高資料庫效能和解決資料庫容量問題。

例子

首先我們舉個大表的例子,你負責的資料庫有一個交易資料儲存表,已經有了200GB的資料。假設已經儲存了5年的資料,但是在去年,因為業務量的增加,這個表的資料量翻了一翻。現在我們來總結一下,你現在擁有一個儲存5年資料的大表,但是你的應用程式通常只需要查詢1到3個月的資料,在此之前資料程式是不會去查詢,可能有些時候,某個人需要定位問題或對帳會查詢1年之內的資料,或者資料分析部門需要對近三年的資料進行彙總生成報表資料,基於以上考慮,為了滿足這些需求,表裡的資料不能丟,也不能刪除 ,我們通常會將這些資料儲存在1個表裡,來方便給各個查詢需求提供資料支援。

但是,這麼龐大一張表,這種方式會極大的影響了資料庫的效能,所以我們考慮可以嘗試將上面三種應用查詢場景的資料分別放在3個表裡,來解決這種效能問題:

  1. 第一個表存放近期三個月資料,用於線上高頻業務查詢。

  2. 第二個歸檔表儲存所有的歷史資料用於低頻查詢,例如排查問題或者對賬。

  3. 第三個是用於儲存報告的彙總表。

有了上面這些表,我們就遵循單一責任的原則,為各種查詢的需求提供最好的效能。首先我們有一個最近3個月資料的主表,可以大大提高查詢效能和擴充套件性。舉個例子,假如資料的容量在未來3-5年內每年都會翻倍,但是你的主表也只是用到這麼多資料的子集。比如你三個月的主表資料為20GB,那麼下一年就是40GB,再後一年也只有80GB,這些資料量也是非常容易管理的。另外隨著時間的推移,軟體和硬體也在不斷改進和升級,所以可以通過升級和更新,可以不斷保證業務的效能。我們將冷資料和熱資料分別儲存到不同的資料表中,這樣也可以使得擴充套件性得到長期的保證。

如何實施歸檔

1.建立歸檔表_archive

這種方式是通過建立一個以_archive結尾的歸檔表來實施的。如果使用這種方式,那麼一般需要在業務層進行查詢的分離改造,比如基於我們的特定歸檔規則 ,對業務端核心程式碼改造或者使用proxy方案等來決定是使用主表還是歸檔表。同時我們還需要一個數據歸檔過程,當資料過時或者變成冷資料時,將該資料從主表遷移到歸檔表中。

在業務層查詢時,我們可以通過時間欄位來進行查詢判斷,例如將90天之前的資料在歸檔表中查詢,否則就在主表查詢。另一種方式可以通過增加status列去判斷查詢主表還是歸檔表,如果是inactive則查詢歸檔表,否則就在主表查詢。

2.根據日期進行分割槽

這種方式是通過對錶進行分割槽來實現,雖然這是一種不同的物理資料模型,但是確實有助於將表的資料進行拆分到不同的物理磁碟,並且不需要程式碼的任何改造。作為DBA,一般對錶進行分割槽是比較常用的方式,我們可以通過日期欄位很容易確定哪些是冷資料,並根據日期將不同日期的時間分配到不同的分割槽中,在查詢的時候,我們可以通過日期來從分割槽中快速定位到對應的資料,同時建立分割槽表也比較利於DBA對大表進行管理操作。

請看下面的例子,通過下面方式,我們可以將資料按照日期進行分配到正確的分割槽.

CREATE TABLE `largetable` (

  `id` bigint unsigned NOT NULL AUTO_INCREMENT,

 `dateCreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,

  `status` int default 1,
  `sometext` text,

  PRIMARY KEY (`id`,`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Query OK, 0 rows affected (0.03 sec)

mysql> alter table largetable partition by RANGE(YEAR(dateCreated)) (

-> PARTITION p2016 VALUES LESS THAN (2017),

-> PARTITION p2017 VALUES LESS THAN (2018),

-> PARTITION p2018 VALUES LESS THAN (2019),

-> PARTITION p2019 VALUES LESS THAN (2020),

-> PARTITION p2020 VALUES LESS THAN (2021),

-> PARTITION pmax VALUES LESS THAN MAXVALUE);

Query OK, 0 rows affected (0.05 sec)

Records: 0  Duplicates: 0  Warnings: 0

在上面的例子中,我們根據資料行的建立時間,按年將資料放入到不同的分割槽,這裡需要注意的是在2020年以後,我們還需要在表裡新增新的年份,當然我們可以提前加更多的分割槽或者部署指令碼來自動化建立新的分割槽。

3.通過狀態進行分割槽

我們也可以通過status狀態列來進行分割槽,這種情況下,通常狀態列會包含active/inactive兩種狀態,然後通過update進行狀態列的更新(使用replace或者insert+delete也是可以的),將資料放入到正確的分割槽當中。請看下面的示例:

mysql> CREATE TABLE `largetable` (

->   `id` bigint unsigned NOT NULL AUTO_INCREMENT,

->   `dateCreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,

->   `status` int default 1, — default active

->   `sometext` text,

->   PRIMARY KEY (`id`,`status`)

-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Query OK, 0 rows affected (0.02 sec)

mysql> alter table largetable partition by list(status) (

-> partition pactive values in (1), — active

-> partition pinactive values in (2) — inactive

-> );

Query OK, 0 rows affected (0.03 sec)

Records: 0  Duplicates: 0  Warnings: 0

mysql> select * from largetable partition (pactive);

Empty set (0.00 sec)

mysql> select * from largetable partition (pinactive);

Empty set (0.00 sec)

mysql> insert into largetable(sometext) values (‘hello’);

Query OK, 1 row affected (0.01 sec)

mysql> select * from largetable partition (pinactive);

Empty set (0.00 sec)

mysql> select * from largetable partition (pactive);

+—-+———————+——–+———-+

| id | dateCreated         | status | sometext |

+—-+———————+——–+———-+

|  1 | 2017-10-30 10:04:03 |      1 | hello    |

+—-+———————+——–+———-+

1 row in set (0.00 sec)

mysql> update largetable set status = 2 where id =1 ;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from largetable partition (pactive);

Empty set (0.00 sec)

mysql> select * from largetable partition (pinactive);

+—-+———————+——–+———-+

| id | dateCreated         | status | sometext |

+—-+———————+——–+———-+

|  1 | 2017-10-30 10:04:03 |      2 | hello    |

+—-+———————+——–+———-+

1 row in set (0.00 sec)

4.通過ID進行分割槽

最後一種方式,我們介紹下通過自增ID主鍵列進行分割槽的方式,請看下面的示例:

mysql> CREATE TABLE `largetable` (

->   `id` bigint unsigned NOT NULL AUTO_INCREMENT,

->   `dateCreated` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,

->   `status` int default 1,

->   `sometext` text,

->   PRIMARY KEY (`id`)

-> ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Query OK, 0 rows affected (0.02 sec)

mysql> alter table largetable partition by RANGE(id) (

-> PARTITION p1 VALUES LESS THAN (500000000),

-> PARTITION p2 VALUES LESS THAN (1000000000),

-> PARTITION p3 VALUES LESS THAN (1500000000),

-> PARTITION p4 VALUES LESS THAN (2000000000),

-> PARTITION p5 VALUES LESS THAN (2500000000),

-> PARTITION pmax VALUES LESS THAN MAXVALUE);

Query OK, 0 rows affected (0.06 sec)

Records: 0  Duplicates: 0  Warnings: 0

上面的例子中,我們通過ID列進行了range分割槽,如果業務的查詢基本都是主鍵查詢,那麼這種方式會比較有用。 與按照日期分割槽相比,按照ID分割槽還會有助於資料平均分配到各個分割槽。

最後總結

上述簡單介紹了歸檔表和分割槽的一些方法,但是關鍵的一點是要如何選擇正確的分割槽鍵和分割槽方式,這一點並不容易,我們需要和業務端進行充分溝通業務場景,並根據場景來選擇合適的分割槽鍵,我們選擇的分割槽鍵要能正確分割槽,並且不會降低表的查詢速度。

另外一點,為了讓優化器能將查詢傳送到正確的分割槽鍵,在建立分割槽表的時候,我們需要將分割槽鍵新增到主鍵裡,並且理想情況下,該分割槽鍵能被包含在所有select/update/delete等語句的where條件裡面,否則的話,你的查詢將會按照順序查詢表對應的每個分割槽,這種情況下查詢效能就沒有那麼好了。



相關推薦

MYSQL線上資料庫歸檔方法

 前言 作為一個企業或者DBA,我們通常會有這種想法,資料是一個公司的核心命脈,應該需要永久儲存,很多時候DBA和開發溝通的時候,開發人員也會這麼告訴我們,這份資料非常重要,資料需要永久儲存。然而,如果將資料庫的資料永久儲存,那麼遲早有一天,你會擁有一個非常大的資料庫。

Mysql遍歷Mysql大量資料讀取記憶體溢位的解決方法

mysql jdbc預設把select的所有結果全部取回,放到記憶體中,如果是要遍歷很大的表,則可能把記憶體撐爆。 一種辦法是:用limit,offset,但這樣你會發現取資料的越來越慢,原因是設定了offset,mysql需要將讀取位置移動到offset的位置,隨著offset增大,取資料也越來越慢

Mysql之pt-online-schema-change線上更新加索引

由於目前生產環境中大表比較多,這裡選擇了一個600M的小表做一次線上測試。 環境:Ubuntu 12.04 mysql版本 :5.6.29-log 表引擎:Innodb 一、pt-online-schema-change介紹       percona 公司提供的一款線上

mysql千萬級線上加索引

 create table tmp like paper_author; ALTER TABLE tmp ADD INDEX ( `PaperID` ) insert into tmp(ooo,...)  select  ooo,... from paper_auth

Mysql千萬級優化

數據庫服務 時間段 系統 時也 導致 slave 如何 1.5 傳統 Mysql的單張表的最大數據存儲量尚沒有定論,一般情況下mysql單表記錄超過千萬以後性能會變得很差。因此,總結一些相關的Mysql千萬級大表的優化策略。 1.優化sql以及索引 1.1優化sql

MySQL筆記——資料庫的基本操作

SQL(Structure Query Language)語句        SQL是一種資料庫查詢和程式設計語言,用於存取資料以及查詢、更新和管理關係資料庫系統;同時也是資料庫指令碼檔案的副檔名。SQL語句有以下三種:

MySQL三-----資料庫的基本操作

1.1建立和檢視資料庫 建立資料庫語法: CREATE DATABASE 資料庫名稱 示例:CREATE DATABASE is;建立一個名為is的資料庫; 檢視所有已經存在的資料庫: SHOW DATABASE; 檢視一個已經存在的資料庫的資訊: SHOW CREAT

MySQL修改資料庫、欄位字符集

修改資料庫字符集:   程式碼如下:   ALTER DATABASE db_name DEFAULT CHARACTER SET character_name [COLLATE ...];   把表預設的字符集和所有字元列(CHAR,VARCHAR,TEXT)改為

MySQL千萬級優化解決方案

MySQL千萬級大表優化解決方案 非原創,純屬記錄一下。 背景 無意間看到了這篇文章,作者寫的很棒,於是乎,本人自私一把,把乾貨儲存下來。:-) 問題概述 使用阿里雲rds for MySQL資料庫(就是MySQL5.6版本),有個使用者上網記錄表6個月的資料量近2000萬,保留最近一年的資料量達到

mysql查詢資料庫所有,刪除所有外來鍵,清空所有資料

####mysql命令登入資料庫 1.mysql -u root -ppassword 2.mysql -u root -p Enter password:****提示輸入密碼 3.mysql -h localhost -u root -ppassword 4.mysql -h 1

mysql建立資料庫時設定字符集

建立資料庫及表時設定字符集,避免出現中文亂碼的方法: 建立資料庫 CREATE DATABASE test CHARACTER SET utf8 COLLATE utf8_general_ci; --注意後面三個單詞之間是有下劃線的對於每個選項所給定的值,前面沒有等

mysql判斷資料庫是否存在

(1) 判斷資料庫存在, 則刪除: drop database if exists db_name; (2) 判斷資料表存在, 則刪除: drop table if exists table_name; 注: db_name, table_name可用`

mysql建立資料庫

連線mysql伺服器: shell>mysql -uroot -p 利用quit退出。 檢視目前伺服器中擁有的資料庫: mysql>show databases; 使用資料庫時需要宣告: mysql>use test; 建立一個新的資料庫: mysql&g

PHP MySQL 建立資料庫

建立表 CREATE TABLE 用於在 MySQL 中建立資料庫表。 語法 CREATE TABLE table_name ( column_name1 data_type, column_name2 data_type, column_name3 data_type, ....... ) 為了執行此命令

mysql更改資料庫編碼

第一步:檢視全域性編碼方式 show variables like ‘character%’; 第二步:設定全域性的編碼方式 set character_set_client = utf8; set character_set_connectio

Mysql千萬級優化策略

sid 屬於 基於 卡住 行數 arch 行數據 power 基本原理 1.優化sql以及索引 1.1優化sql 1、有索引但未被用到的情況(不建議) (1)避免like的參數以通配符開頭時 盡量避免Like的參數以通配符開頭,否則數據庫引擎會放棄使用索引而進

MySQL 上億優化實踐

原則 優化 順序 lock slave inno -c slow 其它 目錄 背景 分析 select xxx_record語句 delete xxx_record語句

pt-online-schema-change工具使用教程(線上修改結構)

  percona-toolkit中pt-online-schema-change工具安裝和使用   pt-online-schema-change介紹 使用場景:線上修改大表結構 在資料庫的維護中,總會涉及到生產環境上修改表結構的情況,修改一些小表影響很小,而修改大表時,往往影響業務的正

MySQL——建立資料庫

建立資料庫 -- Firsr way CREATE DATABASE database_name; -- Second way CREATE SCHEMA database_name;   2.建立表 CREATE TABLE birds( bird_id INT AUTO_INCREMENT

mysql資料庫binlog日誌太的清理方法

mysql資料庫binlog日誌太大的清理方法  1.檢視binlog日誌 mysql> show binary logs; +------------------+------------+ | Log_name