首頁 > 資料庫 > mysql教程 > 詳解MySQL分區表的限制與限制的程式碼實例

詳解MySQL分區表的限制與限制的程式碼實例

黄舟
發布: 2017-03-17 14:02:58
原創
1723 人瀏覽過

本文對Mysql分區表的限製做了一些總結,因為個人能力以及測試環境的原因,有可能有錯誤的地方,還請大家看到能及時指出,當然有興趣的朋友可以去官方網站查閱。

禁止建置

分割區運算式不支援下列幾種建置:

儲存程序,儲存函數,UDFS或外掛程式

宣告變數或使用者變數

可以參考分割區不支援的SQL函數

##算術和邏輯運算子

分區表達式支援+,-,*算術運算,但是不支援p和/運算(還存在,可以查看Bug #30188, Bug #33182)。但是,結果必須是整形或

NULL(線性分區鍵除外,想了解更多信息,可以查看分區類型)。

分區表達式不支援

位元運算:|,&,^,<<,>>,~ .

HANDLER語句

在MySQL 5.7.1之前的分割表不支援HANDLER語句,以後的版本取消了這個限制。

伺服器SQL模式

如果要用使用者自訂分割區的表的話,需要注意的是,在建立分割區表時的SQL模式是不保留的。在伺服器SQL模式章節中已經討論過,大多數MySQL函數和運算子的結果可能會根據伺服器SQL模式而改變。所以,一旦SQL模式在建立分割表後改變,可能導致這些表的行為發生重大變化,很容易導致資料遺失或損壞。基於以上原因,強烈建議你在建立分區表後千萬不要修改伺服器的SQL模式。

舉例來說明下上述情況:

1.

錯誤處理

mysql> CREATE TABLE tn (c1 INT)
  ->    PARTITION BY LIST(1 p 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=&#39;STRICT_ALL_TABLES,ERROR_FOR_pISION_BY_ZERO&#39;;
Query OK, 0 rows affected (0.00 sec)
 
mysql> INSERT INTO tn VALUES (NULL), (0), (1);
ERROR 1365 (22012): pision by 0
登入後複製

2.表輔助功能

有時候修改SQL模式可能會導致分區表不可用。例如有些表格只有在SQL模式為NO_UNSIGNED_SUBTRACTION才發揮作用,例如:

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=&#39;NO_UNSIGNED_SUBTRACTION&#39;;
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)
登入後複製

如果你在建立tu後,修改SQL模式,就可能再也不能存取這個表了:

mysql> SET sql_mode=&#39;&#39;;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模式也會影響分割表的複製。在主備間使用不同的SQL模式可能會導致分區表達式主備上執行是不同的結果(而在阿里主備切換是很正常的操作);這也會導致在主備複製過程中,不同分區間的資料分佈不同;也有可能導致在主庫上的分區表insert成功,而備庫上失敗。基於上述情況,最好的解決方法是確保主備間的SQL模式要保持一致(這個是DBA在維運過程中需要注意的)。

效能注意事項

以下是一些會影響分割區操作效能的因素:

#檔案系統操作分割區或重新分割(例如ALTER TABLE ...PARTITION BY ..., REORGANIZE PARTITION, 或REMOVE PARTITIONING )操作取決於檔案系統的實作。意思是說上述操作會受作業系統上,例如:檔案系統的類型和特性,磁碟速度,swap空間,作業系統上的
檔案處理效率,以及MySQL伺服器上的和檔案句柄相關的選項,變數等因素影響。要特別說明的是,你需要保證large_files_support是enabled的,open_files_limit設定是合理的。對於MyISAM引擎的分區表來說,需要增加myisam_max_sort_file_size以提高效能;對於InnoDB表來說,分區或重新分區操作透過enabled innodb_file_per_table效率會更快。

也可以參考分割區的最大數量。

MyISAM和分區檔案描述符

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

假設我們要建立有100個分區的MyISAM表,語句如下:

CREATE TABLE t (c1 VARCHAR(50))
PARTITION BY KEY (c1) PARTITIONS 100
ENGINE=MYISAM;
登入後複製

簡單來講,在這個例子中,雖然我們用的KEY分區,但是檔案描述子的問題,在所有使用

表格引擎是MyISAM的分割區都會遇到,不管是分割區類型是哪一種。但是使用其他儲存引擎(例如InnoDB)的分區表沒有這個問題。

假設你想要重新分割t分割區,想讓它有101個分割區的話,用下面的語句:

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

如果要处理ALTER TABLE语句需要402个文件描述符,原来100个分区*2个+101个新分区*2。这是因为在重新组织表数据时,必须打开所有的(新旧)分区。所以建议在执行这些操作时,要确保--open-files-limit要设置的大些。

表锁

对表执行分区操作的进程会占用表的写锁,不影响读,例如在这些分区上的INSERT和UPDATE操作只有在分区操作完成后才能执行。

存储引擎

分区操作,比如查询,和更新操作通常情况下用MyISAM引擎要比InnoDB和NDB快。

索引;分区修剪

分区表和非分区表一样,合理的利用索引可以显著地提升查询速度。另外,设计分区表以及在这些表上的查询,可以利用分区修剪来显著提升性能。

在MySQL 5.7.3版本之前,分区表不支持索引条件下推,之后的版本可以支持了。

load data性能

在MySQL 5.7,load data 使用buffer提高性能。你需要知道的是buffer会占用每个分区的130KB来达到这个目的。

分区的最大个数

如果不是用NDB作为存储引擎的分区表,支持分区(这里子分区也包含在内)最大个数是8192。

如果使用NDB作为存储引擎的用户自定义分区的最大分区个数,取决于MySQL Cluster的版本, 数据节点和其他因素。

如果你创建一个非常多(比最大分区数要少)的分区时,遇到诸如Got error ... from storage engine: Out of resources when opening file类的错误,你可能需要增加open_files_limit。但是open_files_limit其实也依赖操作系统,可能不是所有的平台都可以建议调整。还有一些其他情况,不建议使用巨大或者成百上千个分区,所以使用越来越多的分区并不见得能带来好结果。

不支持Query cache

分区表不支持query cache,在分区表的查询中自动避开了query cache。也就是说在分区表的查询语句中query cache是不起作用的。

每个分区一个key caches

在MySQL 5.7版本中,可以通过CACHE INDEX和LOAD INDEX INTO CACHE来使用MyISAM分区表的key cache。可以为一个,几个或者所有分区都定义key cache,这样可以把一个,几个或者所有分区的索引预加载到key cache中。

不支持InnoDB分区表的外键

使用InnoDB引擎的分区表不支持外键。下面的两种具体情况来阐述:

在InnoDB表不能使用包含有外键的自定义分区;如果已经使用了外键的InnoDB表,则不能被分区。

InnoDB表不能包含一个和用户自定义分区表相关的外键;使用了用户自定义分区的InnoDB表,不能包含和外键相关的列。

刚刚列出的限制的范围包括使用InnoDB存储引擎的所有表。违反这些限制的CREATE TABLE和ALTER TABLE语句是不被允许的。

ALTER TABLE ... ORDER BY

如果在分区表上执行ALTER TABLE ... ORDER BY的话,会导致每个分区的行排序。

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

在某些情况下是需要修改表的primary key的,如果你的应用程序使用了REPLACE语句,这些语句的结果可能会被大幅度修改。

全文索引

分区表不支持全文索引或者搜索,即使分区表的存储引擎是InnoDB或者MyISAM也不行。

空间列

分区表不支持空间列,比如点或者几何。

临时表

不能对临时表进行分区(Bug #17497)。

日志表

不能对日志表进行分区,如果强制执行ALTER TABLE ... PARTITION BY ... 语句会报错。

分区键的数据类型

分区键必须是整形或者结果是整形的表达式。不能用结果为ENUM类型的表达式。因为这种类型的表达式可能是NULL。

下面两种情况是例外的:

当用LINER分区时,可以使用除TEXT或者BLOBS以外的数据类型作为分区键,因为MySQL内部的 hash函数会从这些列中产生正确的数据类型。例如,下面的创建语句是合法的:

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

CREATE TABLE tke
  ( c1 ENUM(&#39;red&#39;, &#39;orange&#39;, &#39;yellow&#39;, &#39;green&#39;, &#39;blue&#39;, &#39;indigo&#39;, &#39;violet&#39;) )
PARTITION BY LINEAR KEY(c1)
PARTITIONS 6;
登入後複製

当用RANGE,LIST,DATE或者DATETIME列分区的话,可能会用string。例如,下面的创建语句是合法的:

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

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

上述异常都不适用于BLOB或TEXT列类型。

子查询

即使子查询避开整形值或者NULL值,分区键不能子查询。

子分区的问题

子分区必须使用HASH或者KEY分区。只有RANGE和LIST分区支持被子分区;HASH和KEY不支持被子分区。

SUBPARTITION BY KEY要求显示指定子分区列,不像PARTITION BY KEY可以省略(这种情况下会默认使用表的primary key)。例如,如果是这样创建表:

CREATE TABLE ts (
  id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(30)
);
登入後複製

你也可以使用相同的列的创建分区表(以KEY分区),使用下面语句:

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;
登入後複製

但是,如果尝试使用缺省列作为子分区列,创建子分区表的话,以下语句将失败,必须指定该语句才能执行成功,如下所示:(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 &#39;)
 
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)
登入後複製

数据字典和索引字典选项

分区表的数据字典和索引字典受以下因素制约:

表级的数据字典和索引字典被忽略(Bug #32091)

在Windows系统上,MyISAM分区表不支持独立分区或子分区的数据字典和索引字典选项。但是支持InnoDB分区表的独立分区或者子分区的数据字典。

修复和重建分区表

分区表支持CHECK TABLE, OPTIMIZE TABLE, ANALYZE TABLE, 和 REPAIR TABLE语句。

另外,你也可以用ALTER TABLE ... REBUILD PARTITION在一个分区表上重建一个或多个分区;用ALTER TABLE ... REORGANIZE PARTITION同样可以重建分区。

从MySQL 5.7.2开始,子分区支持ANALYZE, CHECK, OPTIMIZE, REPAIR, 和 TRUNCATE操作。而在MySQL5.7.5之前的版本就已经引入REBUILD语法,只是不起作用(可以参考Bug #19075411, Bug #73130)。

分区表不支持mysqlcheck, myisamchk, 和 myisampack操作。

导出选项

在MySQL 5.7.4以前的版本,不支持InnoDB分区表的FLUSH TABLES语句的导出选项(Bug #16943907)。

以上是詳解MySQL分區表的限制與限制的程式碼實例的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板