mysql 分區表 測試實驗例子

無論創建何種類型的分區,如果表中存在主鍵或唯一索引的列,則分區列必須是主鍵或唯一索引的一部分。索引列可以是null值。
在沒有主鍵和唯一索引的表中可以指定任意列爲索引列。表中只能最多有一個唯一索引,即primary key 和unique key不能同時存在,primary key包含在unique key中時除外。

如對id分區,1千萬一個區,分了100個區,當查id=1時,沒分區時原來的索引就會對全表走索引,分區後,會直接查第1個區。

1.新建normal_table - 正常表,1千萬數據
  新建area_table - 分區表,1千萬數據
CREATE TABLE `normal_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `key_num` int(11) NOT NULL DEFAULT '0' COMMENT '索引數字',
  `num` int(11) NOT NULL DEFAULT '0' COMMENT '普通數字',
  PRIMARY KEY (`ID`),
  KEY `key_num` (`key_num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='正常表,1千萬數據';

CREATE TABLE `area_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `key_num` int(11) NOT NULL DEFAULT '0' COMMENT '索引數字',
  `num` int(11) NOT NULL DEFAULT '0' COMMENT '普通數字',
  PRIMARY KEY (`ID`),
  KEY `key_num` (`key_num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='分區表,1千萬數據'
PARTITION BY RANGE COLUMNS(id) (
    PARTITION p0 VALUES LESS THAN(1000001),
    PARTITION p1 VALUES LESS THAN(2000001),
    PARTITION p2 VALUES LESS THAN(3000001),
    PARTITION p3 VALUES LESS THAN(4000001),
    PARTITION p4 VALUES LESS THAN(5000001),
    PARTITION p5 VALUES LESS THAN(6000001),
    PARTITION p6 VALUES LESS THAN(7000001),
    PARTITION p7 VALUES LESS THAN(8000001),
    PARTITION p8 VALUES LESS THAN(9000001),
    PARTITION p9 VALUES LESS THAN(MAXVALUE)
);

SELECT * from area_table WHERE num BETWEEN 0 and 990000;
8.375s,無索引
SELECT * from normal_table WHERE num BETWEEN 0 and 990000;
8.590s,無索引

SELECT * from area_table WHERE key_num BETWEEN 0 and 990000;
4.029s,能使用索引
SELECT * from normal_table WHERE key_num BETWEEN 0 and 990000;
9.345s,不能使用索引

SELECT * from area_table WHERE key_num BETWEEN 0 and 2500000;
12.000s,能使用索引
SELECT * from normal_table WHERE key_num BETWEEN 0 and 2500000;
16.365s,不能使用索引

SELECT * from area_table WHERE id BETWEEN 0 and 2500000;
18.544s,能使用主鍵,只掃描p0,p1,p2分片
SELECT * from normal_table WHERE id BETWEEN 0 and 2500000;
19.478s,能使用主鍵

SELECT * from area_table WHERE id BETWEEN 0 and 990000;
3.964s,能使用主鍵,只掃描p0分片
SELECT * from normal_table WHERE id BETWEEN 0 and 990000;
3.807s,能使用主鍵

2.新建big_normal_table - 正常表,8千萬數據
  新建big_area_table - 分區表,8千萬數據
CREATE TABLE `big_normal_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `key_num` int(11) NOT NULL DEFAULT '0' COMMENT '索引數字',
  `num` int(11) NOT NULL DEFAULT '0' COMMENT '普通數字',
  PRIMARY KEY (`ID`),
  KEY `key_num` (`key_num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='大正常表,八千萬數據';

CREATE TABLE `big_area_table` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `key_num` int(11) NOT NULL DEFAULT '0' COMMENT '索引數字',
  `num` int(11) NOT NULL DEFAULT '0' COMMENT '普通數字',
  PRIMARY KEY (`ID`),
  KEY `key_num` (`key_num`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='大分區表,8千萬數據'
PARTITION BY RANGE COLUMNS(id) (
    PARTITION p0 VALUES LESS THAN(10000001),
    PARTITION p1 VALUES LESS THAN(20000001),
    PARTITION p2 VALUES LESS THAN(30000001),
    PARTITION p3 VALUES LESS THAN(40000001),
    PARTITION p4 VALUES LESS THAN(50000001),
    PARTITION p5 VALUES LESS THAN(60000001),
    PARTITION p6 VALUES LESS THAN(70000001),
    PARTITION p7 VALUES LESS THAN(80000001),
    PARTITION p8 VALUES LESS THAN(90000001),
    PARTITION p9 VALUES LESS THAN(MAXVALUE)
);

SELECT * from big_area_table WHERE num BETWEEN 0 and 990000;
43.883s,無索引
SELECT * from normal_table WHERE num BETWEEN 0 and 990000;
43.557s,無索引

SELECT * from big_area_table WHERE key_num BETWEEN 0 and 990000;
3.889s,能使用索引
SELECT * from normal_table WHERE key_num BETWEEN 0 and 990000;
3.940s,能使用索引

SELECT * from big_area_table WHERE key_num BETWEEN 0 and 2000000;
15.603s,能使用索引
SELECT * from normal_table WHERE key_num BETWEEN 0 and 2000000;
14.556s,能使用索引

SELECT * from big_area_table WHERE key_num BETWEEN 0 and 8000000;
86.228s,能使用索引
SELECT * from normal_table WHERE key_num BETWEEN 0 and 8000000;
77.976s,能使用索引

EXPLAIN SELECT * from big_area_table WHERE key_num BETWEEN 8000000 and 15000000;
56.523s,能使用索引
EXPLAIN SELECT * from normal_table WHERE key_num BETWEEN 8000000 and 15000000;
88.527s,不能使用索引

SELECT * from big_area_table WHERE id BETWEEN 0 and 8000000;
41.931s,只掃描p0分片,能使用主鍵
SELECT * from normal_table WHERE id BETWEEN 0 and 8000000;
41.806s,能使用主鍵

以上實驗可得:
用一般字段查詢時,分區表和正常表差別不大,因爲都用不到索引和主鍵,都是全表查詢,所以速度差別不大。

用索引查詢時,對某些查詢(常見於數據量較大的查詢),分區錶速度會快一些,分區表能用到索引,正常表用不到索引,
猜測原因是正常表判斷這個索引查詢範圍數據量太大,走索引效率也不高,所以直接全表掃描了;
而分區表通過索引定位到主鍵時,發現這些主鍵只在某幾個分區,這樣只查這幾個分區就效率很快,比全表掃描要好,就可以走索引了。

用主鍵查詢時,分區表和正常表差別不大,因爲都是走主鍵,所以速度差別不大。

總結:
當你的表是千萬級的,且需要走某個索引去查數據,但因爲查的數據量過大走不了索引時,可以考慮用分區表。
比如一個訂單表,有個功能要查1年來的訂單明細,就算對訂單時間加了索引,但數據量太大還是走不了索引,這時就可考慮用分區表了。

ps:
-- 創建存儲過程插入數據
DROP PROCEDURE IF EXISTS add_data;
DELIMITER $$
CREATE PROCEDURE add_data()
BEGIN
DECLARE i INT;
  SET i=1;
  WHILE(i<=10000000) DO
    insert into normal_table(key_num,num) values(i, i);
    insert into area_table(key_num,num) values(i, i);
    SET i=i+1;
  END WHILE;
END;
$$
DELIMITER;
-- 調用存儲過程
call add_data();

--查詢每個分區的數據量
SELECT
	partition_name,
	partition_expression,
	table_rows
FROM
	information_schema.PARTITIONS
WHERE
	table_schema = SCHEMA()
AND table_name = 'area_table';

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章