佳木斯湛栽影视文化发展公司

主頁 > 知識庫 > MySQL分區(qū)表的局限和限制詳解

MySQL分區(qū)表的局限和限制詳解

熱門標簽:網(wǎng)站排名優(yōu)化 服務外包 Linux服務器 地方門戶網(wǎng)站 AI電銷 呼叫中心市場需求 鐵路電話系統(tǒng) 百度競價排名

禁止構建

分區(qū)表達式不支持以下幾種構建:

存儲過程,存儲函數(shù),UDFS或者插件

聲明變量或者用戶變量

可以參考分區(qū)不支持的SQL函數(shù)

算術和邏輯運算符

分區(qū)表達式支持+,-,*算術運算,但是不支持DIV和/運算(還存在,可以查看Bug #30188, Bug #33182)。但是,結果必須是整形或者NULL(線性分區(qū)鍵除外,想了解更多信息,可以查看分區(qū)類型)。

分區(qū)表達式不支持位運算:|,,^,,>>,~ .

HANDLER語句

在MySQL 5.7.1之前的分區(qū)表不支持HANDLER語句,以后的版本取消了這一限制。

服務器SQL模式

如果要用用戶自定義分區(qū)的表的話,需要注意的是,在創(chuàng)建分區(qū)表時的SQL模式是不保留的。在服務器SQL模式一章中已經(jīng)討論過,大多數(shù)MySQL函數(shù)和運算符的結果可能會根據(jù)服務器SQL模式而改變。所以,一旦SQL模式在創(chuàng)建分區(qū)表后改變,可能導致這些表的行為發(fā)生重大變化,很容易導致數(shù)據(jù)丟失或者損壞。基于以上原因,強烈建議你在創(chuàng)建分區(qū)表后千萬不要修改服務器的SQL模式。

舉個例子來說明下上述情況:

1.錯誤處理

mysql> CREATE TABLE tn (c1 INT)
  ->    PARTITION BY LIST(1 DIV c1) (
  ->    PARTITION p0 VALUES IN (NULL),
  ->    PARTITION p1 VALUES IN (1)
  -> );
  Query OK, 0 rows affected (0.05 sec)

MySQL默認除以0的結果是NULL,而不是報錯:

mysql> SELECT @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|      |
+------------+
1 row in set (0.00 sec)
 
mysql> INSERT INTO tn VALUES (NULL), (0), (1);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0

然而如果我們修改SQL模式的話,就會報錯:

mysql> SET sql_mode='STRICT_ALL_TABLES,ERROR_FOR_DIVISION_BY_ZERO';
Query OK, 0 rows affected (0.00 sec)
 
mysql> INSERT INTO tn VALUES (NULL), (0), (1);
ERROR 1365 (22012): Division by 0


2.表輔助功能

有時候修改SQL模式可能會導致分區(qū)表不可用。比如有些表只有在SQL模式為NO_UNSIGNED_SUBTRACTION才發(fā)揮作用,比如:

mysql> SELECT @@sql_mode;
+------------+
| @@sql_mode |
+------------+
|      |
+------------+
1 row in set (0.00 sec)
 
mysql> CREATE TABLE tu (c1 BIGINT UNSIGNED)
  ->   PARTITION BY RANGE(c1 - 10) (
  ->   PARTITION p0 VALUES LESS THAN (-5),
  ->   PARTITION p1 VALUES LESS THAN (0),
  ->   PARTITION p2 VALUES LESS THAN (5),
  ->   PARTITION p3 VALUES LESS THAN (10),
  ->   PARTITION p4 VALUES LESS THAN (MAXVALUE)
  -> );
ERROR 1563 (HY000): Partition constant is out of partition function domain
   
mysql> SET sql_mode='NO_UNSIGNED_SUBTRACTION';
Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT @@sql_mode;
+-------------------------+
| @@sql_mode       |
+-------------------------+
| NO_UNSIGNED_SUBTRACTION |
+-------------------------+
1 row in set (0.00 sec)
 
mysql> CREATE TABLE tu (c1 BIGINT UNSIGNED)
  ->   PARTITION BY RANGE(c1 - 10) (
  ->   PARTITION p0 VALUES LESS THAN (-5),
  ->   PARTITION p1 VALUES LESS THAN (0),
  ->   PARTITION p2 VALUES LESS THAN (5),
  ->   PARTITION p3 VALUES LESS THAN (10),
  ->   PARTITION p4 VALUES LESS THAN (MAXVALUE)
  -> );
   
Query OK, 0 rows affected (0.05 sec)

如果你在創(chuàng)建tu后,修改SQL模式,就可能再也不能訪問這個表了:

mysql> SET sql_mode='';Query OK, 0 rows affected (0.00 sec)
 
mysql> SELECT * FROM tu;
ERROR 1563 (HY000): Partition constant is out of partition function domain
 
mysql> INSERT INTO tu VALUES (20);
ERROR 1563 (HY000): Partition constant is out of partition function domain

服務器端的SQL模式也會影響分區(qū)表的復制。在主備間使用不同的SQL模式可能會導致分區(qū)表達式主備上執(zhí)行是不同的結果(而在阿里主備切換是很正常的操作);這也會導致在主備復制過程中,不同分區(qū)間的數(shù)據(jù)分布不同;也有可能導致在主庫上的分區(qū)表insert成功,而備庫上失敗。基于上述情況,最好的解決辦法是保證主備間的SQL模式要保持一致(這個是DBA在運維過程中需要注意的)。

性能注意事項

下面是一些會影響分區(qū)操作性能的因素:

文件系統(tǒng)操作
分區(qū)或者重新分區(qū)(比如ALTER TABLE ...PARTITION BY ..., REORGANIZE PARTITION, 或者REMOVE PARTITIONING )操作取決于文件系統(tǒng)的實現(xiàn)。意思是說上述操作會受操作系統(tǒng)上,比如:文件系統(tǒng)的類型和特性,磁盤速度,swap空間,操作系統(tǒng)上的文件處理效率,以及MySQL服務器上的和文件句柄相關的選項,變量等因素影響。需要特別說明的是,你需要保證large_files_support是enabled的,open_files_limit設置是合理的。對于MyISAM引擎的分區(qū)表來說,需要增加myisam_max_sort_file_size以提高性能;對于InnoDB表來說,分區(qū)或者重新分區(qū)操作通過enabled innodb_file_per_table效率會更快。

也可以參考分區(qū)的最大數(shù)量。

MyISAM和分區(qū)文件描述符

對于MyISAM分區(qū)表來說,MySQL為每個打開的表,每個分區(qū)使用兩個文件描述符。這也就意味著,在MyISAM分區(qū)表上想執(zhí)行操作(特別是ALTER TABLE操作)比相同的表沒有分區(qū),需要更多的文件描述符。

假設我們要創(chuàng)建有100個分區(qū)的MyISAM表,語句如下:

CREATE TABLE t (c1 VARCHAR(50))
PARTITION BY KEY (c1) PARTITIONS 100
ENGINE=MYISAM;

簡單來講,在這個例子中,雖然我們用的KEY分區(qū),但是文件描述符的問題,在所有使用表引擎是MyISAM的分區(qū)里都會遇到,不管是分區(qū)類型是哪種。但是使用其他存儲引擎(比如InnoDB)的分區(qū)表沒有這個問題。

假設你想對t重新分區(qū),想讓它有101個分區(qū)的話,使用下面的語句:

ALTER TABLE t PARTITION BY KEY (c1) PARTITIONS 101;

如果要處理ALTER TABLE語句需要402個文件描述符,原來100個分區(qū)*2個+101個新分區(qū)*2。這是因為在重新組織表數(shù)據(jù)時,必須打開所有的(新舊)分區(qū)。所以建議在執(zhí)行這些操作時,要確保--open-files-limit要設置的大些。

表鎖

對表執(zhí)行分區(qū)操作的進程會占用表的寫鎖,不影響讀,例如在這些分區(qū)上的INSERT和UPDATE操作只有在分區(qū)操作完成后才能執(zhí)行。

存儲引擎

分區(qū)操作,比如查詢,和更新操作通常情況下用MyISAM引擎要比InnoDB和NDB快。

索引;分區(qū)修剪

分區(qū)表和非分區(qū)表一樣,合理的利用索引可以顯著地提升查詢速度。另外,設計分區(qū)表以及在這些表上的查詢,可以利用分區(qū)修剪來顯著提升性能。

在MySQL 5.7.3版本之前,分區(qū)表不支持索引條件下推,之后的版本可以支持了。

load data性能

在MySQL 5.7,load data 使用buffer提高性能。你需要知道的是buffer會占用每個分區(qū)的130KB來達到這個目的。

分區(qū)的最大個數(shù)

如果不是用NDB作為存儲引擎的分區(qū)表,支持分區(qū)(這里子分區(qū)也包含在內)最大個數(shù)是8192。

如果使用NDB作為存儲引擎的用戶自定義分區(qū)的最大分區(qū)個數(shù),取決于MySQL Cluster的版本, 數(shù)據(jù)節(jié)點和其他因素。

如果你創(chuàng)建一個非常多(比最大分區(qū)數(shù)要少)的分區(qū)時,遇到諸如Got error ... from storage engine: Out of resources when opening file類的錯誤,你可能需要增加open_files_limit。但是open_files_limit其實也依賴操作系統(tǒng),可能不是所有的平臺都可以建議調整。還有一些其他情況,不建議使用巨大或者成百上千個分區(qū),所以使用越來越多的分區(qū)并不見得能帶來好結果。

不支持Query cache

分區(qū)表不支持query cache,在分區(qū)表的查詢中自動避開了query cache。也就是說在分區(qū)表的查詢語句中query cache是不起作用的。

每個分區(qū)一個key caches

在MySQL 5.7版本中,可以通過CACHE INDEX和LOAD INDEX INTO CACHE來使用MyISAM分區(qū)表的key cache。可以為一個,幾個或者所有分區(qū)都定義key cache,這樣可以把一個,幾個或者所有分區(qū)的索引預加載到key cache中。

不支持InnoDB分區(qū)表的外鍵

使用InnoDB引擎的分區(qū)表不支持外鍵。下面的兩種具體情況來闡述:

在InnoDB表不能使用包含有外鍵的自定義分區(qū);如果已經(jīng)使用了外鍵的InnoDB表,則不能被分區(qū)。

InnoDB表不能包含一個和用戶自定義分區(qū)表相關的外鍵;使用了用戶自定義分區(qū)的InnoDB表,不能包含和外鍵相關的列。

剛剛列出的限制的范圍包括使用InnoDB存儲引擎的所有表。違反這些限制的CREATE TABLE和ALTER TABLE語句是不被允許的。

ALTER TABLE ... ORDER BY

如果在分區(qū)表上執(zhí)行ALTER TABLE ... ORDER BY的話,會導致每個分區(qū)的行排序。

REPLACE語句在修改primary key上的效率

在某些情況下是需要修改表的primary key的,如果你的應用程序使用了REPLACE語句,這些語句的結果可能會被大幅度修改。

全文索引

分區(qū)表不支持全文索引或者搜索,即使分區(qū)表的存儲引擎是InnoDB或者MyISAM也不行。

空間列

分區(qū)表不支持空間列,比如點或者幾何。

臨時表

不能對臨時表進行分區(qū)(Bug #17497)。

日志表

不能對日志表進行分區(qū),如果強制執(zhí)行ALTER TABLE ... PARTITION BY ... 語句會報錯。

分區(qū)鍵的數(shù)據(jù)類型

分區(qū)鍵必須是整形或者結果是整形的表達式。不能用結果為ENUM類型的表達式。因為這種類型的表達式可能是NULL。

下面兩種情況是例外的:

當用LINER分區(qū)時,可以使用除TEXT或者BLOBS以外的數(shù)據(jù)類型作為分區(qū)鍵,因為MySQL內部的 hash函數(shù)會從這些列中產(chǎn)生正確的數(shù)據(jù)類型。例如,下面的創(chuàng)建語句是合法的:

CREATE TABLE tkc (c1 CHAR)
PARTITION BY KEY(c1)
PARTITIONS 4;

CREATE TABLE tke
  ( c1 ENUM('red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet') )
PARTITION BY LINEAR KEY(c1)
PARTITIONS 6;

當用RANGE,LIST,DATE或者DATETIME列分區(qū)的話,可能會用string。例如,下面的創(chuàng)建語句是合法的:

CREATE TABLE rc (c1 INT, c2 DATE)
PARTITION BY RANGE COLUMNS(c2) (
  PARTITION p0 VALUES LESS THAN('1990-01-01'),
  PARTITION p1 VALUES LESS THAN('1995-01-01'),
  PARTITION p2 VALUES LESS THAN('2000-01-01'),
  PARTITION p3 VALUES LESS THAN('2005-01-01'),
  PARTITION p4 VALUES LESS THAN(MAXVALUE)
);

CREATE TABLE lc (c1 INT, c2 CHAR(1))
PARTITION BY LIST COLUMNS(c2) (
  PARTITION p0 VALUES IN('a', 'd', 'g', 'j', 'm', 'p', 's', 'v', 'y'),
  PARTITION p1 VALUES IN('b', 'e', 'h', 'k', 'n', 'q', 't', 'w', 'z'),
  PARTITION p2 VALUES IN('c', 'f', 'i', 'l', 'o', 'r', 'u', 'x', NULL)
);

上述異常都不適用于BLOB或TEXT列類型。

子查詢

即使子查詢避開整形值或者NULL值,分區(qū)鍵不能子查詢。

子分區(qū)的問題

子分區(qū)必須使用HASH或者KEY分區(qū)。只有RANGE和LIST分區(qū)支持被子分區(qū);HASH和KEY不支持被子分區(qū)。

SUBPARTITION BY KEY要求顯示指定子分區(qū)列,不像PARTITION BY KEY可以省略(這種情況下會默認使用表的primary key)。例如,如果是這樣創(chuàng)建表:

CREATE TABLE ts (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(30)
);

你也可以使用相同的列的創(chuàng)建分區(qū)表(以KEY分區(qū)),使用下面語句:

CREATE TABLE ts (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(30)
)
PARTITION BY KEY()
PARTITIONS 4;

前面的語句其實和下面的語句是一樣的:

CREATE TABLE ts (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(30)
)
PARTITION BY KEY(id)
PARTITIONS 4;
 

但是,如果嘗試使用缺省列作為子分區(qū)列,創(chuàng)建子分區(qū)表的話,以下語句將失敗,必須指定該語句才能執(zhí)行成功,如下所示:(bug已知 Bug #51470)。

mysql> CREATE TABLE ts (
  ->   id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  ->   name VARCHAR(30)
  -> )
  -> PARTITION BY RANGE(id)
  -> SUBPARTITION BY KEY()
  -> SUBPARTITIONS 4
  -> (
  ->   PARTITION p0 VALUES LESS THAN (100),
  ->   PARTITION p1 VALUES LESS THAN (MAXVALUE)
  -> );
   
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use near ')
 
mysql> CREATE TABLE ts (
  ->   id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  ->   name VARCHAR(30)
  -> )
  -> PARTITION BY RANGE(id)
  -> SUBPARTITION BY KEY(id)
  -> SUBPARTITIONS 4
  -> (
  ->   PARTITION p0 VALUES LESS THAN (100),
  ->   PARTITION p1 VALUES LESS THAN (MAXVALUE)
  -> );
   
Query OK, 0 rows affected (0.07 sec)


數(shù)據(jù)字典和索引字典選項

分區(qū)表的數(shù)據(jù)字典和索引字典受以下因素制約:

表級的數(shù)據(jù)字典和索引字典被忽略(Bug #32091)

在Windows系統(tǒng)上,MyISAM分區(qū)表不支持獨立分區(qū)或子分區(qū)的數(shù)據(jù)字典和索引字典選項。但是支持InnoDB分區(qū)表的獨立分區(qū)或者子分區(qū)的數(shù)據(jù)字典。

修復和重建分區(qū)表

分區(qū)表支持CHECK TABLE, OPTIMIZE TABLE, ANALYZE TABLE, 和 REPAIR TABLE語句。

另外,你也可以用ALTER TABLE ... REBUILD PARTITION在一個分區(qū)表上重建一個或多個分區(qū);用ALTER TABLE ... REORGANIZE PARTITION同樣可以重建分區(qū)。

從MySQL 5.7.2開始,子分區(qū)支持ANALYZE, CHECK, OPTIMIZE, REPAIR, 和 TRUNCATE操作。而在MySQL5.7.5之前的版本就已經(jīng)引入REBUILD語法,只是不起作用(可以參考Bug #19075411, Bug #73130)。

分區(qū)表不支持mysqlcheck, myisamchk, 和 myisampack操作。

導出選項

在MySQL 5.7.4以前的版本,不支持InnoDB分區(qū)表的FLUSH TABLES語句的導出選項(Bug #16943907)。

參考資料

https://dev.mysql.com/doc/refman/5.7/en/partitioning-limitations.html

https://www.slideshare.net/datacharmer/mysql-partitions-tutorial/34-Partition_pruning_unpartitioned_tableexplain_partitions

https://www.percona.com/blog/2010/12/11/mysql-partitioning-can-save-you-or-kill-you/

您可能感興趣的文章:
  • mysql實現(xiàn)查詢最接近的記錄數(shù)據(jù)示例
  • 詳解MySQL恢復psc文件記錄數(shù)為0的解決方案
  • PHP+MySQL統(tǒng)計該庫中每個表的記錄數(shù)并按遞減順序排列的方法
  • MySQL數(shù)據(jù)庫查看數(shù)據(jù)表占用空間大小和記錄數(shù)的方法
  • MYSQL速度慢的問題 記錄數(shù)據(jù)庫語句
  • MySQL通過觸發(fā)器解決數(shù)據(jù)庫中表的行數(shù)限制詳解及實例
  • MySQL 如何限制一張表的記錄數(shù)

標簽:湖南 蘭州 衡水 仙桃 湘潭 銅川 黃山 崇左

巨人網(wǎng)絡通訊聲明:本文標題《MySQL分區(qū)表的局限和限制詳解》,本文關鍵詞  ;如發(fā)現(xiàn)本文內容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內容系統(tǒng)采集于網(wǎng)絡,涉及言論、版權與本站無關。
  • 相關文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    外汇| 双辽市| 拉孜县| 北辰区| 若羌县| 秀山| 咸阳市| 汉源县| 高州市| 赤峰市| 巫山县| 河津市| 微山县| 七台河市| 大理市| 彰武县| 广州市| 双城市| 伊春市| 越西县| 梁平县| 新安县| 富蕴县| 砚山县| 巧家县| 博爱县| 东台市| 娄烦县| 福海县| 仁化县| 涿州市| 兴文县| 旬阳县| 沂南县| 无极县| 宁明县| 两当县| 卓资县| 东海县| 瑞金市| 濉溪县|