Õ¾ÄÚËÑË÷: ÇëÊäÈëËÑË÷¹Ø¼ü´Ê
µ±Ç°Ò³Ãæ: ÔÚÏßÎĵµÊ×Ò³ > MySQL 5.1²Î¿¼ÊÖ²áÖÐÎÄ°æ

Chapter 18. Partitioning - MySQL 5.1²Î¿¼ÊÖ²áÖÐÎÄ°æ

第18章:分区

本章讨论MySQL 5.1.中实现的分区。关于分区和分区概念的介ç»å¯ä»¥åœ¨18.1节,“MySQL中的分区概述â€ä¸­æ‰¾åˆ°ã€‚MySQL 5.1 支æŒå“ªå‡ ç§ç±»åž‹çš„分区,在18.2节,“分区类型†中讨论。关于å­åˆ†åŒºåœ¨18.2.5节,“å­åˆ†åŒºâ€ 中讨论。现有分区表中分区的增加ã€åˆ é™¤å’Œä¿®æ”¹çš„方法在18.3节,“分区管ç†â€ 中介ç»ã€‚ 和分区表一åŒä½¿ç”¨çš„表维护命令在18.3.3节,“分区维护†中介ç»ã€‚

请注æ„:MySQL 5.1中的分区实现ä»ç„¶å¾ˆæ–°ï¼ˆpre-alphaå“质),此时还ä¸æ˜¯å¯ç”Ÿäº§çš„(not production-ready)。 åŒæ ·ï¼Œè®¸å¤šä¹Ÿé€‚用于本章:在这里æ述的一些功能还没有实际上实现(分区维护和é‡æ–°åˆ†åŒºå‘½ä»¤ï¼‰ï¼Œå…¶ä»–çš„å¯èƒ½è¿˜æ²¡æœ‰å®Œå…¨å¦‚所æ述的那样实现(例如, 用于分区的数æ®ç›®å½•ï¼ˆDATA DIRECTORY)和索引目录(INDEX DIRECTORY)选项å—到Bug #13520) ä¸åˆ©çš„å½±å“). 我们已ç»è®¾æ³•åœ¨æœ¬ç« ä¸­æ ‡å‡ºè¿™äº›å·®å¼‚。在æ出缺陷报告å‰ï¼Œæˆ‘们鼓励å‚考下é¢çš„一些资æºï¼š

  • MySQL 分区论å›

    这是一个为对MySQL分区技术感兴趣或用MySQL分区技术åšè¯•éªŒæ供的官方讨论论å›ã€‚æ¥è‡ªMySQL çš„å¼€å‘者和其他的人,会在上é¢å‘表和更新有关的æ料。它由分区开å‘和文献团队的æˆå‘˜è´Ÿè´£ç›‘控。

  • 分区缺陷报告

    å·²ç»å½’档在缺陷系统中的ã€æ‰€æœ‰åˆ†åŒºç¼ºé™·çš„一个列表,而无论这些缺陷的年é™ã€ä¸¥é‡æ€§æˆ–当å‰çš„状æ€å¦‚何。根æ®è®¸å¤šè§„则å¯ä»¥å¯¹è¿™äº›ç¼ºé™·è¿›è¡Œç­›é€‰ï¼Œæˆ–者å¯ä»¥ä»ŽMySQL缺陷系统主页开始,然åŽæŸ¥æ‰¾ä½ ç‰¹åˆ«æ„Ÿå…´è¶£çš„缺陷。

  • Mikael Ronström's Blog

    MySQL分区体系结构和领先的开å‘者Mikael Ronström ç»å¸¸åœ¨è¿™é‡Œè´´å…³äºŽä»–研究MySQL 分区和MySQL簇的文章。

  • PlanetMySQL

    一个MySQL 新闻网站,它以汇集MySQL相关的网誌为特点,那些使用我的MySQL的人应该对此有兴趣。我们鼓励查看那些研究MySQL分区的人的网誌链接,或者把你自己的网誌加到这些新闻报é“中。

MySQL 5.1的二进制版本目å‰è¿˜ä¸å¯ç”¨ï¼›ä½†æ˜¯ï¼Œå¯ä»¥ä»ŽBitKeeper知识库中获得æºç ã€‚è¦æ¿€æ´»åˆ†åŒºï¼Œéœ€è¦ä½¿ç”¨--with-分区选项编译æœåŠ¡å™¨ã€‚关于建立MySQL 的更多信æ¯ï¼Œè¯·å‚è§2.8节,“使用æºç åˆ†å‘版安装MySQLâ€ã€‚如果在编译一个激活分区的MySQL 5.1创建中碰到问题,å¯ä»¥åœ¨MySQL分区论å›ä¸­æŸ¥æ‰¾è§£å†³åŠžæ³•ï¼Œå¦‚果在论å›ä¸­å·²ç»è´´å‡ºçš„文章中没有找到问题的解决办法,å¯ä»¥åœ¨ä¸Šé¢å¯»æ‰¾å¸®åŠ©ã€‚

18.1. MySQL中的分区概述

本节æ供了关于MySQL 5.1.分区在概念上的概述。

SQL标准在数æ®å­˜å‚¨çš„物ç†æ–¹é¢æ²¡æœ‰æ供太多的指å—。SQL语言的使用独立于它所使用的任何数æ®ç»“构或图表ã€è¡¨ã€è¡Œæˆ–列下的介质。但是,大部分高级数æ®åº“管ç†ç³»ç»Ÿå·²ç»å¼€å‘了一些根æ®æ–‡ä»¶ç³»ç»Ÿã€ç¡¬ä»¶æˆ–者这两者æ¥ç¡®å®šå°†è¦ç”¨äºŽå­˜å‚¨ç‰¹å®šæ•°æ®å—物ç†ä½ç½®çš„方法。在MySQL中,InnoDB存储引擎长期支æŒè¡¨ç©ºé—´çš„概念,并且MySQLæœåŠ¡å™¨ç”šè‡³åœ¨åˆ†åŒºå¼•å…¥ä¹‹å‰ï¼Œå°±èƒ½é…置为存储ä¸åŒçš„æ•°æ®åº“使用ä¸åŒçš„物ç†è·¯å¾„(关于如何é…置的解释,请å‚è§7.6.1节,“使用符å·é“¾æŽ¥â€)。

分区åˆæŠŠè¿™ä¸ªæ¦‚念推进了一步,它å…许根æ®å¯ä»¥è®¾ç½®ä¸ºä»»æ„大å°çš„规则,跨文件系统分é…å•ä¸ªè¡¨çš„多个部分。实际上,表的ä¸åŒéƒ¨åˆ†åœ¨ä¸åŒçš„ä½ç½®è¢«å­˜å‚¨ä¸ºå•ç‹¬çš„表。用户所选择的ã€å®žçŽ°æ•°æ®åˆ†å‰²çš„规则被称为分区函数,这在MySQL中它å¯ä»¥æ˜¯æ¨¡æ•°ï¼Œæˆ–者是简å•çš„匹é…一个连续的数值区间或数值列表,或者是一个内部HASH函数,或一个线性HASH函数。函数根æ®ç”¨æˆ·æŒ‡å®šçš„分区类型æ¥é€‰æ‹©ï¼ŒæŠŠç”¨æˆ·æ供的表达å¼çš„值作为å‚数。该表达å¼å¯ä»¥æ˜¯ä¸€ä¸ªæ•´æ•°åˆ—值,或一个作用在一个或多个列值上并返回一个整数的函数。这个表达å¼çš„值传递给分区函数,分区函数返回一个表示那个特定记录应该ä¿å­˜åœ¨å“ªä¸ªåˆ†åŒºçš„åºå·ã€‚这个函数ä¸èƒ½æ˜¯å¸¸æ•°ï¼Œä¹Ÿä¸èƒ½æ˜¯ä»»æ„数。它ä¸èƒ½åŒ…å«ä»»ä½•æŸ¥è¯¢ï¼Œä½†æ˜¯å®žé™…上å¯ä»¥ä½¿ç”¨MySQL 中任何å¯ç”¨çš„SQL表达å¼ï¼Œåªè¦è¯¥è¡¨è¾¾å¼è¿”回一个å°äºŽMAXVALUE(最大å¯èƒ½çš„正整数)的正数值。分区函数的例å­å¯ä»¥åœ¨æœ¬ç« åŽé¢å…³äºŽåˆ†åŒºç±»åž‹çš„讨论中找到 (请å‚è§18.2节,“分区类型†),也å¯åœ¨13.1.5节,“CREATE TABLE语法â€çš„分区语法æ述中找到。

当二进制ç å˜æˆå¯ç”¨æ—¶ï¼ˆä¹Ÿå°±æ˜¯è¯´ï¼Œ5.1 -max 二进制ç å°†é€šè¿‡--with-partition 建立),分区支æŒå°±å°†åŒ…å«åœ¨MySQL 5.1çš„-max 版本中。如果MySQL二进制ç æ˜¯ä½¿ç”¨åˆ†åŒºæ”¯æŒå»ºç«‹çš„,那么激活它ä¸éœ€è¦ä»»ä½•å…¶ä»–的东西 (例如,在my.cnf 文件中,ä¸éœ€è¦ç‰¹æ®Šçš„æ¡ç›®)。å¯ä»¥é€šè¿‡ä½¿ç”¨SHOW VARIABLES命令æ¥ç¡®å®šMySQL是å¦æ”¯æŒåˆ†åŒºï¼Œä¾‹å¦‚:

mysql> SHOW VARIABLES LIKE '%partition%';
 
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| have_partition_engine | YES   |
+-----------------------+-------+
1 row in set (0.00 sec)

在如上列出的一个正确的SHOW VARIABLES 命令所产生的输出中,如果没有看到å˜é‡have_partition_engine的值为YES,那么MySQL的版本就ä¸æ”¯æŒåˆ†åŒºã€‚(注æ„:在显示任何有关分区支æŒä¿¡æ¯çš„命令SHOW ENGINES的输出中,ä¸ä¼šç»™å‡ºä»»ä½•ä¿¡æ¯ï¼›å¿…须使用SHOW VARIABLES命令æ¥åšå‡ºè¿™ä¸ªåˆ¤æ–­ï¼‰ã€‚

对于创建了分区的表,å¯ä»¥ä½¿ç”¨ä½ çš„MySQL æœåŠ¡å™¨æ‰€æ”¯æŒçš„任何存储引擎;MySQL 分区引擎在一个å•ç‹¬çš„层中è¿è¡Œï¼Œå¹¶ä¸”å¯ä»¥å’Œä»»ä½•è¿™æ ·çš„层进行相互作用。在MySQL 5.1版中,åŒä¸€ä¸ªåˆ†åŒºè¡¨çš„所有分区必须使用åŒä¸€ä¸ªå­˜å‚¨å¼•æ“Žï¼›ä¾‹å¦‚,ä¸èƒ½å¯¹ä¸€ä¸ªåˆ†åŒºä½¿ç”¨MyISAM,而对å¦ä¸€ä¸ªä½¿ç”¨InnoDB。但是,这并ä¸å¦¨ç¢åœ¨åŒä¸€ä¸ª MySQL æœåŠ¡å™¨ä¸­ï¼Œç”šè‡³åœ¨åŒä¸€ä¸ªæ•°æ®åº“中,对于ä¸åŒçš„分区表使用ä¸åŒçš„存储引擎。

è¦ä¸ºæŸä¸ªåˆ†åŒºè¡¨é…置一个专门的存储引擎,必须且åªèƒ½ä½¿ç”¨[STORAGE] ENGINE 选项,这如åŒä¸ºéžåˆ†åŒºè¡¨é…置存储引擎一样。但是,必须记ä½[STORAGE] ENGINE(和其他的表选项)必须列在用在CREATE TABLE语å¥ä¸­çš„其他任何分区选项之å‰ã€‚下é¢çš„例å­ç»™å‡ºäº†æ€Žæ ·åˆ›å»ºä¸€ä¸ªé€šè¿‡HASH分æˆ6个分区ã€ä½¿ç”¨InnoDB存储引擎的表:

CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
    ENGINE=INNODB
    PARTITION BY HASH(MONTH(tr_date))
    PARTITIONS 6;

(注释:æ¯ä¸ªPARTITION å­å¥å¯ä»¥åŒ…å«ä¸€ä¸ª [STORAGE] ENGINE 选项,但是在MySQL 5.1版本中,这没有作用)。

创建分区的临时表也是å¯èƒ½çš„;但是,这ç§è¡¨çš„生命周期åªæœ‰å½“å‰MySQL 的会è¯çš„时间那么长。对于éžåˆ†åŒºçš„临时表,这也是一样的。

注释:分区适用于一个表的所有数æ®å’Œç´¢å¼•ï¼›ä¸èƒ½åªå¯¹æ•°æ®åˆ†åŒºè€Œä¸å¯¹ç´¢å¼•åˆ†åŒºï¼Œå之亦然,åŒæ—¶ä¹Ÿä¸èƒ½åªå¯¹è¡¨çš„一部分进行分区。

å¯ä»¥é€šè¿‡ä½¿ç”¨ç”¨æ¥åˆ›å»ºåˆ†åŒºè¡¨çš„CREATE TABLE语å¥çš„PARTITIONå­å¥çš„DATA DIRECTORY(数æ®è·¯å¾„)和INDEX DIRECTORY(索引路径)选项,为æ¯ä¸ªåˆ†åŒºçš„æ•°æ®å’Œç´¢å¼•æŒ‡å®šç‰¹å®šçš„路径。此外,MAX_ROWSå’ŒMIN_ROWS选项å¯ä»¥ç”¨æ¥è®¾å®šæœ€å¤§å’Œæœ€å°çš„行数,它们å¯ä»¥å„自ä¿å­˜åœ¨æ¯ä¸ªåˆ†åŒºé‡Œã€‚关于这些选项的更多信æ¯ï¼Œè¯·å‚è§18.3节,“分区管ç†â€ã€‚注释:这个特殊的功能由于Bug #13250的原因,目å‰è¿˜ä¸èƒ½å®žç”¨ã€‚在第一个5.1二进制版本投入使用时,我们应该已ç»æŠŠè¿™ä¸ªé—®é¢˜è§£å†³äº†ã€‚

分区的一些优点包括:

·         与å•ä¸ªç£ç›˜æˆ–文件系统分区相比,å¯ä»¥å­˜å‚¨æ›´å¤šçš„æ•°æ®ã€‚

·         对于那些已ç»å¤±åŽ»ä¿å­˜æ„义的数æ®ï¼Œé€šå¸¸å¯ä»¥é€šè¿‡åˆ é™¤ä¸Žé‚£äº›æ•°æ®æœ‰å…³çš„分区,很容易地删除那些数æ®ã€‚相å地,在æŸäº›æƒ…况下,添加新数æ®çš„过程åˆå¯ä»¥é€šè¿‡ä¸ºé‚£äº›æ–°æ•°æ®ä¸“门增加一个新的分区,æ¥å¾ˆæ–¹ä¾¿åœ°å®žçŽ°ã€‚

通常和分区有关的其他优点包括下é¢åˆ—出的这些。MySQL 分区中的这些功能目å‰è¿˜æ²¡æœ‰å®žçŽ°ï¼Œä½†æ˜¯åœ¨æˆ‘们的优先级列表中,具有高的优先级;我们希望在5.1的生产版本中,能包括这些功能。

·         一些查询å¯ä»¥å¾—到æžå¤§çš„优化,这主è¦æ˜¯å€ŸåŠ©äºŽæ»¡è¶³ä¸€ä¸ªç»™å®šWHERE 语å¥çš„æ•°æ®å¯ä»¥åªä¿å­˜åœ¨ä¸€ä¸ªæˆ–多个分区内,这样在查找时就ä¸ç”¨æŸ¥æ‰¾å…¶ä»–剩余的分区。因为分区å¯ä»¥åœ¨åˆ›å»ºäº†åˆ†åŒºè¡¨åŽè¿›è¡Œä¿®æ”¹ï¼Œæ‰€ä»¥åœ¨ç¬¬ä¸€æ¬¡é…置分区方案时还ä¸æ›¾è¿™ä¹ˆåšæ—¶ï¼Œå¯ä»¥é‡æ–°ç»„织数æ®ï¼Œæ¥æ高那些常用查询的效率。

·         涉åŠåˆ°ä¾‹å¦‚SUM() å’Œ COUNT()这样èšåˆå‡½æ•°çš„查询,å¯ä»¥å¾ˆå®¹æ˜“地进行并行处ç†ã€‚è¿™ç§æŸ¥è¯¢çš„一个简å•ä¾‹å­å¦‚ “SELECT salesperson_id, COUNT(orders) as order_total FROM sales GROUP BY salesperson_idï¼›â€ã€‚通过“并行â€ï¼Œ è¿™æ„味ç€è¯¥æŸ¥è¯¢å¯ä»¥åœ¨æ¯ä¸ªåˆ†åŒºä¸ŠåŒæ—¶è¿›è¡Œï¼Œæœ€ç»ˆç»“æžœåªéœ€é€šè¿‡æ€»è®¡æ‰€æœ‰åˆ†åŒºå¾—到的结果。

·         通过跨多个ç£ç›˜æ¥åˆ†æ•£æ•°æ®æŸ¥è¯¢ï¼Œæ¥èŽ·å¾—更大的查询åžåé‡ã€‚

è¦ç»å¸¸æ£€æŸ¥æœ¬é¡µå’Œæœ¬ç« ï¼Œå› ä¸ºå®ƒå°†éšMySQL 5.1åŽç»­çš„分区进展而更新。

18.2. åˆ†åŒºç±»åž‹

本节讨论在MySQL 5.1中å¯ç”¨çš„分区类型。这些类型包括:

·         RANGE 分区:基于属于一个给定连续区间的列值,把多行分é…给分区。å‚è§18.2.1节,“RANGE分区â€ã€‚

·         LIST 分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹é…一个离散值集åˆä¸­çš„æŸä¸ªå€¼æ¥è¿›è¡Œé€‰æ‹©ã€‚å‚è§18.2.2节,“LIST分区â€ã€‚

·         HASH分区:基于用户定义的表达å¼çš„返回值æ¥è¿›è¡Œé€‰æ‹©çš„分区,该表达å¼ä½¿ç”¨å°†è¦æ’入到表中的这些行的列值进行计算。这个函数å¯ä»¥åŒ…å«MySQL 中有效的ã€äº§ç”Ÿéžè´Ÿæ•´æ•°å€¼çš„任何表达å¼ã€‚å‚è§18.2.3节,“HASH分区â€ã€‚

·         KEY 分区:类似于按HASH分区,区别在于KEY分区åªæ”¯æŒè®¡ç®—一列或多列,且MySQL æœåŠ¡å™¨æ供其自身的哈希函数。必须有一列或多列包å«æ•´æ•°å€¼ã€‚å‚è§18.2.4节,“KEY分区â€ã€‚

无论使用何ç§ç±»åž‹çš„分区,分区总是在创建时就自动的顺åºç¼–å·ï¼Œä¸”从0开始记录,记ä½è¿™ä¸€ç‚¹éžå¸¸é‡è¦ã€‚当有一新行æ’入到一个分区表中时,就是使用这些分区编å·æ¥è¯†åˆ«æ­£ç¡®çš„分区。例如,如果你的表使用4个分区,那么这些分区就编å·ä¸º0, 1, 2, å’Œ3。对于RANGEå’ŒLIST分区类型,确认æ¯ä¸ªåˆ†åŒºç¼–å·éƒ½å®šä¹‰äº†ä¸€ä¸ªåˆ†åŒºï¼Œå¾ˆæœ‰å¿…è¦ã€‚对HASH分区,使用的用户函数必须返回一个大于0的整数值。对于KEY分区,这个问题通过MySQLæœåŠ¡å™¨å†…部使用的 哈希函数自动进行处ç†ã€‚

分区的å字基本上éµå¾ªå…¶ä»–MySQL 标识符应当éµå¾ªçš„原则,例如用于表和数æ®åº“å字的标识符。但是应当注æ„,分区的å字是ä¸åŒºåˆ†å¤§å°å†™çš„。例如,下é¢çš„CREATE TABLE语å¥å°†ä¼šäº§ç”Ÿå¦‚下的错误:

mysql> CREATE TABLE t2 (val INT)
    -> PARTITION BY LIST(val)(
    ->     PARTITION mypart VALUES IN (1,3,5),
    ->     PARTITION MyPart VALUES IN (2,4,6)
    -> );
错误1488 (HY000): 表的所有分区必须有唯一的å字。

这是因为MySQL认为分区åå­—mypartå’ŒMyPart没有区别。

注释:在下é¢çš„章节中,我们没有必è¦æä¾›å¯ä»¥ç”¨æ¥åˆ›å»ºæ¯ç§åˆ†åŒºç±»åž‹è¯­æ³•çš„所有å¯èƒ½å½¢å¼ï¼Œè¿™äº›ä¿¡æ¯å¯ä»¥åœ¨13.1.5节,“CREATE TABLE语法†中找到。

18.2.1. RANGE分区

按照RANGE分区的表是通过如下一ç§æ–¹å¼è¿›è¡Œåˆ†åŒºçš„,æ¯ä¸ªåˆ†åŒºåŒ…å«é‚£äº›åˆ†åŒºè¡¨è¾¾å¼çš„值ä½äºŽä¸€ä¸ªç»™å®šçš„连续区间内的行。这些区间è¦è¿žç»­ä¸”ä¸èƒ½ç›¸äº’é‡å ï¼Œä½¿ç”¨VALUES LESS THANæ“作符æ¥è¿›è¡Œå®šä¹‰ã€‚在下é¢çš„几个例å­ä¸­ï¼Œå‡å®šä½ åˆ›å»ºäº†ä¸€ä¸ªå¦‚下的一个表,该表ä¿å­˜æœ‰20家音åƒåº—çš„èŒå‘˜è®°å½•ï¼Œè¿™20家音åƒåº—çš„ç¼–å·ä»Ž1到20。

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)ï¼›

æ ¹æ®ä½ çš„需è¦ï¼Œè¿™ä¸ªè¡¨å¯ä»¥æœ‰å¤šç§æ–¹å¼æ¥æŒ‰ç…§åŒºé—´è¿›è¡Œåˆ†åŒºã€‚一ç§æ–¹å¼æ˜¯ä½¿ç”¨store_id 列。例如,你å¯èƒ½å†³å®šé€šè¿‡æ·»åŠ ä¸€ä¸ªPARTITION BY RANGEå­å¥æŠŠè¿™ä¸ªè¡¨åˆ†å‰²æˆ4个区间,如下所示:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN (21)
)ï¼›

按照这ç§åˆ†åŒºæ–¹æ¡ˆï¼Œåœ¨å•†åº—1到5工作的雇员相对应的所有行被ä¿å­˜åœ¨åˆ†åŒºP0中,商店6到10的雇员ä¿å­˜åœ¨P1中,ä¾æ¬¡ç±»æŽ¨ã€‚注æ„,æ¯ä¸ªåˆ†åŒºéƒ½æ˜¯æŒ‰é¡ºåºè¿›è¡Œå®šä¹‰ï¼Œä»Žæœ€ä½Žåˆ°æœ€é«˜ã€‚这是PARTITION BY RANGE 语法的è¦æ±‚;在这点上,它类似于C或Java中的“switch ... caseâ€è¯­å¥ã€‚

对于包å«æ•°æ®(72, 'Michael', 'Widenius', '1998-06-25', NULL, 13)的一个新行,å¯ä»¥å¾ˆå®¹æ˜“地确定它将æ’入到p2分区中,但是如果增加了一个编å·ä¸ºç¬¬21的商店,将会å‘生什么呢?在这ç§æ–¹æ¡ˆä¸‹ï¼Œç”±äºŽæ²¡æœ‰è§„则把store_id大于20的商店包å«åœ¨å†…,æœåŠ¡å™¨å°†ä¸çŸ¥é“把该行ä¿å­˜åœ¨ä½•å¤„,将会导致错误。 è¦é¿å…è¿™ç§é”™è¯¯ï¼Œå¯ä»¥é€šè¿‡åœ¨CREATE TABLE语å¥ä¸­ä½¿ç”¨ä¸€ä¸ªâ€œcatchall†VALUES LESS THANå­å¥ï¼Œè¯¥å­å¥æ供给所有大于明确指定的最高值的值:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (store_id) (
    PARTITION p0 VALUES LESS THAN (6),
    PARTITION p1 VALUES LESS THAN (11),
    PARTITION p2 VALUES LESS THAN (16),
    PARTITION p3 VALUES LESS THAN MAXVALUE
)ï¼›

MAXVALUE 表示最大的å¯èƒ½çš„整数值。现在,store_id 列值大于或等于16(定义了的最高值)的所有行都将ä¿å­˜åœ¨åˆ†åŒºp3中。在将æ¥çš„æŸä¸ªæ—¶å€™ï¼Œå½“商店数已ç»å¢žé•¿åˆ°25, 30, 或更多 ,å¯ä»¥ä½¿ç”¨ALTER TABLE语å¥ä¸ºå•†åº—21-25, 26-30,等等增加新的分区 (关于如何实现的详细信æ¯å‚è§18.3节,“分区管ç†â€ )。

在几乎一样的结构中,你还å¯ä»¥åŸºäºŽé›‡å‘˜çš„工作代ç æ¥åˆ†å‰²è¡¨ï¼Œä¹Ÿå°±æ˜¯è¯´ï¼ŒåŸºäºŽjob_code 列值的连续区间。例如——å‡å®š2ä½æ•°å­—的工作代ç ç”¨æ¥è¡¨ç¤ºæ™®é€šï¼ˆåº—内的)工人,三个数字代ç è¡¨ç¤ºåŠžå…¬å®¤å’Œæ”¯æŒäººå‘˜ï¼Œå››ä¸ªæ•°å­—代ç è¡¨ç¤ºç®¡ç†å±‚,你å¯ä»¥ä½¿ç”¨ä¸‹é¢çš„语å¥åˆ›å»ºè¯¥åˆ†åŒºè¡¨ï¼š

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT NOT NULL,
    store_id INT NOT NULL
)
PARTITION BY RANGE (job_code) (
    PARTITION p0 VALUES LESS THAN (100),
    PARTITION p1 VALUES LESS THAN (1000),
    PARTITION p2 VALUES LESS THAN (10000)
)ï¼›

在这个例å­ä¸­, 店内工人相关的所有行将ä¿å­˜åœ¨åˆ†åŒºp0中,办公室和支æŒäººå‘˜ç›¸å…³çš„所有行ä¿å­˜åœ¨åˆ†åŒºp1中,管ç†å±‚相关的所有行ä¿å­˜åœ¨åˆ†åŒºp2中。

在VALUES LESS THAN å­å¥ä¸­ä½¿ç”¨ä¸€ä¸ªè¡¨è¾¾å¼ä¹Ÿæ˜¯å¯èƒ½çš„。这里最值得注æ„çš„é™åˆ¶æ˜¯MySQL 必须能够计算表达å¼çš„返回值作为LESS THAN (<)比较的一部分;因此,表达å¼çš„值ä¸èƒ½ä¸ºNULL 。由于这个原因,雇员表的hired, separated, job_code,å’Œstore_id列已ç»è¢«å®šä¹‰ä¸ºéžç©ºï¼ˆNOT NULL)。

除了å¯ä»¥æ ¹æ®å•†åº—ç¼–å·åˆ†å‰²è¡¨æ•°æ®å¤–,你还å¯ä»¥ä½¿ç”¨ä¸€ä¸ªåŸºäºŽä¸¤ä¸ªDATE (日期)中的一个的表达å¼æ¥åˆ†å‰²è¡¨æ•°æ®ã€‚例如,å‡å®šä½ æƒ³åŸºäºŽæ¯ä¸ªé›‡å‘˜ç¦»å¼€å…¬å¸çš„年份æ¥åˆ†å‰²è¡¨ï¼Œä¹Ÿå°±æ˜¯è¯´ï¼ŒYEAR(separated)的值。实现这ç§åˆ†åŒºæ¨¡å¼çš„CREATE TABLE 语å¥çš„一个例å­å¦‚下所示:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY RANGE (YEAR(separated)) (
    PARTITION p0 VALUES LESS THAN (1991),
    PARTITION p1 VALUES LESS THAN (1996),
    PARTITION p2 VALUES LESS THAN (2001),
    PARTITION p3 VALUES LESS THAN MAXVALUE
)ï¼›

在这个方案中,在1991å¹´å‰é›‡ä½£çš„所有雇员的记录ä¿å­˜åœ¨åˆ†åŒºp0中,1991年到1995年期间雇佣的所有雇员的记录ä¿å­˜åœ¨åˆ†åŒºp1中, 1996年到2000年期间雇佣的所有雇员的记录ä¿å­˜åœ¨åˆ†åŒºp2中,2000å¹´åŽé›‡ä½£çš„所有工人的信æ¯ä¿å­˜åœ¨p3中。

RANGE分区在如下场åˆç‰¹åˆ«æœ‰ç”¨ï¼š

·         当需è¦åˆ é™¤â€œæ—§çš„â€æ•°æ®æ—¶ã€‚如果你使用上é¢æœ€è¿‘的那个例å­ç»™å‡ºçš„分区方案,你åªéœ€ç®€å•åœ°ä½¿ç”¨ “ALTER TABLE employees DROP PARTITION p0ï¼›â€æ¥åˆ é™¤æ‰€æœ‰åœ¨1991å¹´å‰å°±å·²ç»åœæ­¢å·¥ä½œçš„雇员相对应的所有行。(更多信æ¯è¯·å‚è§13.1.2节,“ALTER TABLE语法†和 18.3节,“分区管ç†â€ï¼‰ã€‚对于有大é‡è¡Œçš„表,这比è¿è¡Œä¸€ä¸ªå¦‚“DELETE FROM employees WHERE YEAR(separated) <= 1990ï¼›â€è¿™æ ·çš„一个DELETE查询è¦æœ‰æ•ˆå¾—多。

·         想è¦ä½¿ç”¨ä¸€ä¸ªåŒ…å«æœ‰æ—¥æœŸæˆ–时间值,或包å«æœ‰ä»Žä¸€äº›å…¶ä»–级数开始增长的值的列。

·         ç»å¸¸è¿è¡Œç›´æŽ¥ä¾èµ–于用于分割表的列的查询。例如,当执行一个如“SELECT COUNT(*) FROM employees WHERE YEAR(separated) = 2000 GROUP BY store_idï¼›â€è¿™æ ·çš„查询时,MySQLå¯ä»¥å¾ˆè¿…速地确定åªæœ‰åˆ†åŒºp2需è¦æ‰«æ,这是因为余下的分区ä¸å¯èƒ½åŒ…å«æœ‰ç¬¦åˆè¯¥WHEREå­å¥çš„任何记录。注释:这ç§ä¼˜åŒ–还没有在MySQL 5.1æºç¨‹åºä¸­å¯ç”¨ï¼Œä½†æ˜¯ï¼Œæœ‰å…³å·¥ä½œæ­£åœ¨è¿›è¡Œä¸­ã€‚

18.2.2. LIST分区

MySQL中的LIST分区在很多方é¢ç±»ä¼¼äºŽRANGE分区。和按照RANGE分区一样,æ¯ä¸ªåˆ†åŒºå¿…须明确定义。它们的主è¦åŒºåˆ«åœ¨äºŽï¼ŒLIST分区中æ¯ä¸ªåˆ†åŒºçš„定义和选择是基于æŸåˆ—的值从属于一个值列表集中的一个值,而RANGE分区是从属于一个连续区间值的集åˆã€‚LIST分区通过使用“PARTITION BY LIST(expr)â€æ¥å®žçŽ°ï¼Œå…¶ä¸­â€œexpr†是æŸåˆ—值或一个基于æŸä¸ªåˆ—值ã€å¹¶è¿”回一个整数值的表达å¼ï¼Œç„¶åŽé€šè¿‡â€œVALUES IN (value_list)â€çš„æ–¹å¼æ¥å®šä¹‰æ¯ä¸ªåˆ†åŒºï¼Œå…¶ä¸­â€œvalue_listâ€æ˜¯ä¸€ä¸ªé€šè¿‡é€—å·åˆ†éš”的整数列表。

注释:在MySQL 5.1中,当使用LIST分区时,有å¯èƒ½åªèƒ½åŒ¹é…整数列表。

ä¸åƒæŒ‰ç…§RANGE定义分区的情形,LIST分区ä¸å¿…声明任何特定的顺åºã€‚关于LIST分区更详细的语法信æ¯ï¼Œè¯·å‚考13.1.5节,“CREATE TABLE语法†。

对于下é¢ç»™å‡ºçš„例å­ï¼Œæˆ‘们å‡å®šå°†è¦è¢«åˆ†åŒºçš„表的基本定义是通过下é¢çš„“CREATE TABLEâ€è¯­å¥æ供的:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)ï¼›

(这和18.2.1节,“RANGE分区†中的例å­ä¸­ä½¿ç”¨çš„是åŒä¸€ä¸ªè¡¨ï¼‰ã€‚ 

å‡å®šæœ‰20个音åƒåº—,分布在4个有ç»é”€æƒçš„地区,如下表所示:

地区

商店ID å·

北区

3, 5, 6, 9, 17

东区

1, 2, 10, 11, 19, 20

西区

4, 12, 13, 14, 18

中心区

7, 8, 15, 16

è¦æŒ‰ç…§å±žäºŽåŒä¸€ä¸ªåœ°åŒºå•†åº—çš„è¡Œä¿å­˜åœ¨åŒä¸€ä¸ªåˆ†åŒºä¸­çš„æ–¹å¼æ¥åˆ†å‰²è¡¨ï¼Œå¯ä»¥ä½¿ç”¨ä¸‹é¢çš„“CREATE TABLEâ€è¯­å¥ï¼š

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY LIST(store_id)
    PARTITION pNorth VALUES IN (3,5,6,9,17),
    PARTITION pEast VALUES IN (1,2,10,11,19,20),
    PARTITION pWest VALUES IN (4,12,13,14,18),
    PARTITION pCentral VALUES IN (7,8,15,16)
)ï¼›

这使得在表中增加或删除指定地区的雇员记录å˜å¾—容易起æ¥ã€‚例如,å‡å®šè¥¿åŒºçš„所有音åƒåº—都å–给了其他公å¸ã€‚那么与在西区音åƒåº—工作雇员相关的所有记录(行)å¯ä»¥ä½¿ç”¨æŸ¥è¯¢â€œALTER TABLE employees DROP PARTITION pWestï¼›â€æ¥è¿›è¡Œåˆ é™¤ï¼Œå®ƒä¸Žå…·æœ‰åŒæ ·ä½œç”¨çš„DELETE (删除)查询“DELETE query DELETE FROM employees WHERE store_id IN (4,12,13,14,18)ï¼›â€æ¯”èµ·æ¥ï¼Œè¦æœ‰æ•ˆå¾—多。

è¦ç‚¹ï¼šå¦‚果试图æ’入列值(或分区表达å¼çš„返回值)ä¸åœ¨åˆ†åŒºå€¼åˆ—表中的一行时,那么“INSERTâ€æŸ¥è¯¢å°†å¤±è´¥å¹¶æŠ¥é”™ã€‚例如,å‡å®šLIST分区的采用上é¢çš„方案,下é¢çš„查询将失败:

INSERT INTO employees VALUES 
    (224, 'Linus', 'Torvalds', '2002-05-01', '2004-10-12', 42, 21);

这是因为“store_idâ€åˆ—值21ä¸èƒ½åœ¨ç”¨äºŽå®šä¹‰åˆ†åŒºpNorth, pEast, pWest,或pCentral的值列表中找到。è¦é‡ç‚¹æ³¨æ„的是,LIST分区没有类似如“VALUES LESS THAN MAXVALUEâ€è¿™æ ·çš„包å«å…¶ä»–值在内的定义。将è¦åŒ¹é…的任何值都必须在值列表中找到。

LIST分区除了能和RANGE分区结åˆèµ·æ¥ç”Ÿæˆä¸€ä¸ªå¤åˆçš„å­åˆ†åŒºï¼Œä¸ŽHASHå’ŒKEY分区结åˆèµ·æ¥ç”Ÿæˆå¤åˆçš„å­åˆ†åŒºä¹Ÿæ˜¯å¯èƒ½çš„。 关于这方é¢çš„讨论,请å‚考18.2.5节,“å­åˆ†åŒºâ€ã€‚

18.2.3. HASH分区

HASH分区主è¦ç”¨æ¥ç¡®ä¿æ•°æ®åœ¨é¢„先确定数目的分区中平å‡åˆ†å¸ƒã€‚在RANGEå’ŒLIST分区中,必须明确指定一个给定的列值或列值集åˆåº”该ä¿å­˜åœ¨å“ªä¸ªåˆ†åŒºä¸­ï¼›è€Œåœ¨HASH分区中,MySQL 自动完æˆè¿™äº›å·¥ä½œï¼Œä½ æ‰€è¦åšçš„åªæ˜¯åŸºäºŽå°†è¦è¢«å“ˆå¸Œçš„列值指定一个列值或表达å¼ï¼Œä»¥åŠæŒ‡å®šè¢«åˆ†åŒºçš„表将è¦è¢«åˆ†å‰²æˆçš„分区数é‡ã€‚

è¦ä½¿ç”¨HASH分区æ¥åˆ†å‰²ä¸€ä¸ªè¡¨ï¼Œè¦åœ¨CREATE TABLE 语å¥ä¸Šæ·»åŠ ä¸€ä¸ªâ€œPARTITION BY HASH (expr)â€å­å¥ï¼Œå…¶ä¸­â€œexprâ€æ˜¯ä¸€ä¸ªè¿”回一个整数的表达å¼ã€‚它å¯ä»¥ä»…仅是字段类型为MySQL 整型的一列的å字。此外,你很å¯èƒ½éœ€è¦åœ¨åŽé¢å†æ·»åŠ ä¸€ä¸ªâ€œPARTITIONS numâ€å­å¥ï¼Œå…¶ä¸­num 是一个éžè´Ÿçš„整数,它表示表将è¦è¢«åˆ†å‰²æˆåˆ†åŒºçš„æ•°é‡ã€‚

例如,下é¢çš„语å¥åˆ›å»ºäº†ä¸€ä¸ªä½¿ç”¨åŸºäºŽâ€œstore_idâ€åˆ—进行 哈希处ç†çš„表,该表被分æˆäº†4个分区:

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH(store_id)
PARTITIONS 4ï¼›

如果没有包括一个PARTITIONSå­å¥ï¼Œé‚£ä¹ˆåˆ†åŒºçš„æ•°é‡å°†é»˜è®¤ä¸º1。 例外: 对于NDB Cluster(簇)表,默认的分区数é‡å°†ä¸Žç°‡æ•°æ®èŠ‚点的数é‡ç›¸åŒï¼Œè¿™ç§ä¿®æ­£å¯èƒ½æ˜¯è€ƒè™‘任何MAX_ROWS 设置,以便确ä¿æ‰€æœ‰çš„行都能åˆé€‚地æ’入到分区中。(å‚è§ç¬¬17章:MySQL簇)。

如果在关键字“PARTITIONSâ€åŽé¢æ²¡æœ‰åŠ ä¸Šåˆ†åŒºçš„æ•°é‡ï¼Œå°†ä¼šå‡ºçŽ°è¯­æ³•é”™è¯¯ã€‚

“exprâ€è¿˜å¯ä»¥æ˜¯ä¸€ä¸ªè¿”回一个整数的SQL表达å¼ã€‚例如,也许你想基于雇用雇员的年份æ¥è¿›è¡Œåˆ†åŒºã€‚è¿™å¯ä»¥é€šè¿‡ä¸‹é¢çš„语å¥æ¥å®žçŽ°ï¼š

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY HASH(YEAR(hired))
PARTITIONS 4ï¼›

“exprâ€è¿˜å¯ä»¥æ˜¯MySQL 中有效的任何函数或其他表达å¼ï¼Œåªè¦å®ƒä»¬è¿”回一个既éžå¸¸æ•°ã€ä¹Ÿéžéšæœºæ•°çš„整数。(æ¢å¥è¯è¯´ï¼Œå®ƒæ—¢æ˜¯å˜åŒ–的但åˆæ˜¯ç¡®å®šçš„)。但是应当记ä½ï¼Œæ¯å½“æ’入或更新(或者å¯èƒ½åˆ é™¤ï¼‰ä¸€è¡Œï¼Œè¿™ä¸ªè¡¨è¾¾å¼éƒ½è¦è®¡ç®—一次;这æ„味ç€éžå¸¸å¤æ‚的表达å¼å¯èƒ½ä¼šå¼•èµ·æ€§èƒ½é—®é¢˜ï¼Œå°¤å…¶æ˜¯åœ¨æ‰§è¡ŒåŒæ—¶å½±å“大é‡è¡Œçš„è¿ç®—(例如批é‡æ’入)的时候。

最有效率的哈希函数是åªå¯¹å•ä¸ªè¡¨åˆ—进行计算,并且它的值éšåˆ—值进行一致地增大或å‡å°ï¼Œå› ä¸ºè¿™è€ƒè™‘了在分区范围上的“修剪â€ã€‚也就是说,表达å¼å€¼å’Œå®ƒæ‰€åŸºäºŽçš„列的值å˜åŒ–越接近,MySQLå°±å¯ä»¥è¶Šæœ‰æ•ˆåœ°ä½¿ç”¨è¯¥è¡¨è¾¾å¼æ¥è¿›è¡ŒHASH分区。

例如,“date_col†是一个DATE(日期)类型的列,那么表达å¼TO_DAYS(date_col)å°±å¯ä»¥è¯´æ˜¯éšåˆ—“date_colâ€å€¼çš„å˜åŒ–而å‘生直接的å˜åŒ–,因为列“date_colâ€å€¼çš„æ¯ä¸ªå˜åŒ–,表达å¼çš„值也将å‘生与之一致的å˜åŒ–。而表达å¼YEAR(date_col)çš„å˜åŒ–就没有表达å¼TO_DAYS(date_col)那么直接,因为ä¸æ˜¯åˆ—“date_colâ€æ¯æ¬¡å¯èƒ½çš„改å˜éƒ½èƒ½ä½¿è¡¨è¾¾å¼YEAR(date_col)å‘生åŒç­‰çš„改å˜ã€‚å³ä¾¿å¦‚此,表达å¼YEAR(date_col)也还是一个用于 哈希函数的ã€å¥½çš„候选表达å¼ï¼Œå› ä¸ºå®ƒéšåˆ—date_col的一部分å‘生直接å˜åŒ–,并且列date_colçš„å˜åŒ–ä¸å¯èƒ½å¼•èµ·è¡¨è¾¾å¼YEAR(date_col)ä¸æˆæ¯”例的å˜åŒ–。

作为对照,å‡å®šæœ‰ä¸€ä¸ªç±»åž‹ä¸ºæ•´åž‹ï¼ˆINT)的ã€åˆ—å为“int_colâ€çš„列。现在考虑表达å¼â€œPOW(5-int_col,3) + 6â€ã€‚这对于哈希函数就是一个ä¸å¥½çš„选择,因为“int_colâ€å€¼çš„å˜åŒ–并ä¸èƒ½ä¿è¯è¡¨è¾¾å¼äº§ç”Ÿæˆæ¯”例的å˜åŒ–。列 “int_colâ€çš„值å‘生一个给定数目的å˜åŒ–,å¯èƒ½ä¼šå¼•èµ·è¡¨è¾¾å¼çš„值产生一个很大ä¸åŒçš„å˜åŒ–。例如,把列“int_colâ€çš„值从5å˜ä¸º6,表达å¼çš„值将产生“ï¼1â€çš„改å˜ï¼Œä½†æ˜¯æŠŠåˆ—“int_colâ€çš„值从6å˜ä¸º7时,表达å¼çš„值将产生“ï¼7â€çš„å˜åŒ–。

æ¢å¥è¯è¯´ï¼Œå¦‚果列值与表达å¼å€¼ä¹‹æ¯”的曲线图越接近由等å¼â€œy=nx(其中n为éžé›¶çš„常数)æ绘出的直线,则该表达å¼è¶Šé€‚åˆäºŽ 哈希。这是因为,表达å¼çš„éžçº¿æ€§è¶Šä¸¥é‡ï¼Œåˆ†åŒºä¸­æ•°æ®äº§ç”Ÿéžå‡è¡¡åˆ†å¸ƒçš„趋势也将越严é‡ã€‚

ç†è®ºä¸Šè®²ï¼Œå¯¹äºŽæ¶‰åŠåˆ°å¤šåˆ—的表达å¼ï¼Œâ€œä¿®å‰ªï¼ˆpruning)â€ä¹Ÿæ˜¯å¯èƒ½çš„,但是è¦ç¡®å®šå“ªäº›é€‚于 哈希是éžå¸¸å›°éš¾å’Œè€—时的。基于这个原因,实际上ä¸æŽ¨è使用涉åŠåˆ°å¤šåˆ—的哈希表达å¼ã€‚

当使用了“PARTITION BY HASHâ€æ—¶ï¼ŒMySQL将基于用户函数结果的模数æ¥ç¡®å®šä½¿ç”¨å“ªä¸ªç¼–å·çš„分区。æ¢å¥è¯ï¼Œå¯¹äºŽä¸€ä¸ªè¡¨è¾¾å¼â€œexprâ€ï¼Œå°†è¦ä¿å­˜è®°å½•çš„分区编å·ä¸ºN ,其中“N = MOD(expr, num)â€ã€‚例如,å‡å®šè¡¨t1 定义如下,它有4个分区:

CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY HASH( YEAR(col3) )
    PARTITIONS 4ï¼›

如果æ’入一个col3列值为'2005-09-15'的记录到表t1中,那么ä¿å­˜è¯¥æ¡è®°å½•çš„分区确定如下:

MOD(YEAR('2005-09-01'),4)
=  MOD(2005,4)
=  1

MySQL 5.1 还支æŒä¸€ä¸ªè¢«ç§°ä¸ºâ€œlinear hashing(线性哈希功能)â€çš„å˜é‡ï¼Œå®ƒä½¿ç”¨ä¸€ä¸ªæ›´åŠ å¤æ‚的算法æ¥ç¡®å®šæ–°è¡Œæ’入到已ç»åˆ†åŒºäº†çš„表中的ä½ç½®ã€‚关于这ç§ç®—法的æ述,请å‚è§18.2.3.1节,“LINEAR HASH分区†。

æ¯å½“æ’入或更新一æ¡è®°å½•ï¼Œç”¨æˆ·å‡½æ•°éƒ½è¦è®¡ç®—一次。当删除记录时,用户函数也å¯èƒ½è¦è¿›è¡Œè®¡ç®—,这å–决于所处的环境。

注释:如果将è¦åˆ†åŒºçš„表有一个唯一的键,那么用æ¥ä½œä¸ºHASH用户函数的自å˜æ•°æˆ–者主键的column_list的自å˜æ•°çš„ä»»æ„列都必须是那个键的一部分。

18.2.3.1. LINEAR HASH分区

MySQL还支æŒçº¿æ€§å“ˆå¸ŒåŠŸèƒ½ï¼Œå®ƒä¸Žå¸¸è§„哈希的区别在于,线性哈希功能使用的一个线性的2的幂(powers-of-two)è¿ç®—法则,而常规 哈希使用的是求哈希函数值的模数。

线性哈希分区和常规哈希分区在语法上的唯一区别在于,在“PARTITION BY†å­å¥ä¸­æ·»åŠ â€œLINEARâ€å…³é”®å­—,如下é¢æ‰€ç¤ºï¼š

CREATE TABLE employees (
    id INT NOT NULL,
    fname VARCHAR(30),
    lname VARCHAR(30),
    hired DATE NOT NULL DEFAULT '1970-01-01',
    separated DATE NOT NULL DEFAULT '9999-12-31',
    job_code INT,
    store_id INT
)
PARTITION BY LINEAR HASH(YEAR(hired))
PARTITIONS 4ï¼›

å‡è®¾ä¸€ä¸ªè¡¨è¾¾å¼expr, 当使用线性哈希功能时,记录将è¦ä¿å­˜åˆ°çš„分区是num 个分区中的分区N,其中N是根æ®ä¸‹é¢çš„算法得到:

1.    找到下一个大于num.çš„ã€2的幂,我们把这个值称为V ,它å¯ä»¥é€šè¿‡ä¸‹é¢çš„å…¬å¼å¾—到:

2.           V = POWER(2, CEILING(LOG(2, num)))

(例如,å‡å®šnum是13。那么LOG(2,13)就是3.7004397181411。 CEILING(3.7004397181411)就是4,则V = POWER(2,4), å³ç­‰äºŽ16)。

3.    设置 N = F(column_list) & (V - 1).

4.    当 N >= num:

·         设置 V = CEIL(V / 2)

·         设置 N = N & (V - 1)

例如,å‡è®¾è¡¨t1,使用线性哈希分区且有4个分区,是通过下é¢çš„语å¥åˆ›å»ºçš„:

CREATE TABLE t1 (col1 INT, col2 CHAR(5), col3 DATE)
    PARTITION BY LINEAR HASH( YEAR(col3) )
    PARTITIONS 6;

现在å‡è®¾è¦æ’入两行记录到表t1中,其中一æ¡è®°å½•col3列值为'2003-04-14',å¦ä¸€æ¡è®°å½•col3列值为'1998-10-19'。第一æ¡è®°å½•å°†è¦ä¿å­˜åˆ°çš„分区确定如下:

V = POWER(2, CEILING(LOG(2,7))) = 8
N = YEAR('2003-04-14') & (8 - 1)
   = 2003 & 7
   = 3
 
(3 >= 6 为å‡ï¼ˆFALSE): 记录将被ä¿å­˜åˆ°#3å·åˆ†åŒºä¸­)

第二æ¡è®°å½•å°†è¦ä¿å­˜åˆ°çš„分区åºå·è®¡ç®—如下:

V = 8
N = YEAR('1998-10-19') & (8-1)
  = 1998 & 7
  = 6
 
(6 >= 4 为真(TRUE): 还需è¦é™„加的步骤)
 
N = 6 & CEILING(5 / 2)
  = 6 & 3
  = 2
 
(2 >= 4 为å‡ï¼ˆFALSE): 记录将被ä¿å­˜åˆ°#2分区中)

按照线性哈希分区的优点在于增加ã€åˆ é™¤ã€åˆå¹¶å’Œæ‹†åˆ†åˆ†åŒºå°†å˜å¾—更加快æ·ï¼Œæœ‰åˆ©äºŽå¤„ç†å«æœ‰æžå…¶å¤§é‡ï¼ˆ1000å‰ï¼‰æ•°æ®çš„表。它的缺点在于,与使用常规HASH分区得到的数æ®åˆ†å¸ƒç›¸æ¯”,å„个分区间数æ®çš„分布ä¸å¤§å¯èƒ½å‡è¡¡ã€‚

18.2.4. KEY分区

按照KEY进行分区类似于按照HASH分区,除了HASH分区使用的用户定义的表达å¼ï¼Œè€ŒKEY分区的 哈希函数是由MySQL æœåŠ¡å™¨æ供。MySQL 簇(Cluster)使用函数MD5()æ¥å®žçŽ°KEY分区;对于使用其他存储引擎的表,æœåŠ¡å™¨ä½¿ç”¨å…¶è‡ªå·±å†…部的 哈希函数,这些函数是基于与PASSWORD()一样的è¿ç®—法则。

“CREATE TABLE ... PARTITION BY KEYâ€çš„语法规则类似于创建一个通过HASH分区的表的规则。它们唯一的区别在于使用的关键字是KEY而ä¸æ˜¯HASH,并且KEY分区åªé‡‡ç”¨ä¸€ä¸ªæˆ–多个列å的一个列表。

通过线性KEY分割一个表也是å¯èƒ½çš„。下é¢æ˜¯ä¸€ä¸ªç®€å•çš„例å­ï¼š

CREATE TABLE tk (
    col1 INT NOT NULL,
    col2 CHAR(5),
    col3 DATE
) 
PARTITION BY LINEAR KEY (col1)
PARTITIONS 3;

在KEY分区中使用关键字LINEAR和在HASH分区中使用具有åŒæ ·çš„作用,分区的编å·æ˜¯é€šè¿‡2的幂(powers-of-two)算法得到,而ä¸æ˜¯é€šè¿‡æ¨¡æ•°ç®—法。关于该算法åŠå…¶è•´æ¶µå¼çš„æ述请å‚考 18.2.3.1节,“LINEAR HASH分区†。

18.2.5. å­åˆ†åŒº

å­åˆ†åŒºæ˜¯åˆ†åŒºè¡¨ä¸­æ¯ä¸ªåˆ†åŒºçš„å†æ¬¡åˆ†å‰²ã€‚例如,考虑下é¢çš„CREATE TABLE 语å¥ï¼š

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE(YEAR(purchased))
    SUBPARTITION BY HASH(TO_DAYS(purchased))
    SUBPARTITIONS 2
    (
        PARTITION p0 VALUES LESS THAN (1990),
        PARTITION p1 VALUES LESS THAN (2000),
        PARTITION p2 VALUES LESS THAN MAXVALUE
    )ï¼›

表ts 有3个RANGE分区。这3个分区中的æ¯ä¸€ä¸ªåˆ†åŒºâ€”—p0, p1, å’Œ p2 ——åˆè¢«è¿›ä¸€æ­¥åˆ†æˆäº†2个å­åˆ†åŒºã€‚实际上,整个表被分æˆäº†3 * 2 = 6个分区。但是,由于PARTITION BY RANGEå­å¥çš„作用,这些分区的头2个åªä¿å­˜â€œpurchasedâ€åˆ—中值å°äºŽ1990的那些记录。

在MySQL 5.1中,对于已ç»é€šè¿‡RANGE或LIST分区了的表å†è¿›è¡Œå­åˆ†åŒºæ˜¯å¯èƒ½çš„。å­åˆ†åŒºæ—¢å¯ä»¥ä½¿ç”¨HASH希分区,也å¯ä»¥ä½¿ç”¨KEY分区。这也被称为å¤åˆåˆ†åŒºï¼ˆcomposite partitioning)。

为了对个别的å­åˆ†åŒºæŒ‡å®šé€‰é¡¹ï¼Œä½¿ç”¨SUBPARTITION å­å¥æ¥æ˜Žç¡®å®šä¹‰å­åˆ†åŒºä¹Ÿæ˜¯å¯èƒ½çš„。例如,创建在å‰é¢ä¾‹å­ä¸­ç»™å‡ºçš„åŒä¸€ä¸ªè¡¨çš„ã€ä¸€ä¸ªæ›´åŠ è¯¦ç»†çš„æ–¹å¼å¦‚下:

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE(YEAR(purchased))
    SUBPARTITION BY HASH(TO_DAYS(purchased))
    (
        PARTITION p0 VALUES LESS THAN (1990)
        (
            SUBPARTITION s0,
            SUBPARTITION s1
        ),
        PARTITION p1 VALUES LESS THAN (2000)
        (
            SUBPARTITION s2,
            SUBPARTITION s3
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE
        (
            SUBPARTITION s4,
            SUBPARTITION s5
        )
    );

几点è¦æ³¨æ„的语法项:

·         æ¯ä¸ªåˆ†åŒºå¿…须有相åŒæ•°é‡çš„å­åˆ†åŒºã€‚

·         如果在一个分区表上的任何分区上使用SUBPARTITION æ¥æ˜Žç¡®å®šä¹‰ä»»ä½•å­åˆ†åŒºï¼Œé‚£ä¹ˆå°±å¿…须定义所有的å­åˆ†åŒºã€‚æ¢å¥è¯è¯´ï¼Œä¸‹é¢çš„语å¥å°†æ‰§è¡Œå¤±è´¥ï¼š

·                CREATE TABLE ts (id INT, purchased DATE)
·                    PARTITION BY RANGE(YEAR(purchased))
·                    SUBPARTITION BY HASH(TO_DAYS(purchased))
·                    (
·                        PARTITION p0 VALUES LESS THAN (1990)
·                        (
·                            SUBPARTITION s0,
·                            SUBPARTITION s1
·                        ),
·                        PARTITION p1 VALUES LESS THAN (2000),
·                        PARTITION p2 VALUES LESS THAN MAXVALUE
·                        (
·                            SUBPARTITION s2,
·                            SUBPARTITION s3
·                        )
·                    )ï¼›

å³ä¾¿è¿™ä¸ªè¯­å¥åŒ…å«äº†ä¸€ä¸ªSUBPARTITIONS 2å­å¥ï¼Œä½†æ˜¯å®ƒä»ç„¶ä¼šæ‰§è¡Œå¤±è´¥ã€‚

·         æ¯ä¸ªSUBPARTITION å­å¥å¿…须包括 (至少)å­åˆ†åŒºçš„一个å字。å¦åˆ™ï¼Œä½ å¯èƒ½è¦å¯¹è¯¥å­åˆ†åŒºè®¾ç½®ä»»ä½•ä½ æ‰€éœ€è¦çš„选项,或者å…许该å­åˆ†åŒºå¯¹é‚£äº›é€‰é¡¹é‡‡ç”¨å…¶é»˜è®¤çš„设置。

·         在æ¯ä¸ªåˆ†åŒºå†…,å­åˆ†åŒºçš„å字必须是唯一的,但是在整个表中,没有必è¦ä¿æŒå”¯ä¸€ã€‚例如,下é¢çš„CREATE TABLE 语å¥æ˜¯æœ‰æ•ˆçš„:

·                CREATE TABLE ts (id INT, purchased DATE)
·                    PARTITION BY RANGE(YEAR(purchased))
·                    SUBPARTITION BY HASH(TO_DAYS(purchased))
·                    (
·                        PARTITION p0 VALUES LESS THAN (1990)
·                        (
·                            SUBPARTITION s0,
·                            SUBPARTITION s1
·                        ),
·                        PARTITION p1 VALUES LESS THAN (2000)
·                        (
·                            SUBPARTITION s0,
·                            SUBPARTITION s1
·                        ),
·                        PARTITION p2 VALUES LESS THAN MAXVALUE
·                        (
·                            SUBPARTITION s0,
·                            SUBPARTITION s1
·                        )
·                    )ï¼›

å­åˆ†åŒºå¯ä»¥ç”¨äºŽç‰¹åˆ«å¤§çš„表,在多个ç£ç›˜é—´åˆ†é…æ•°æ®å’Œç´¢å¼•ã€‚å‡è®¾æœ‰6个ç£ç›˜ï¼Œåˆ†åˆ«ä¸º/disk0, /disk1, /disk2等。现在考虑下é¢çš„例å­ï¼š

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE(YEAR(purchased))
    SUBPARTITION BY HASH(TO_DAYS(purchased))
    (
        PARTITION p0 VALUES LESS THAN (1990)
        (
            SUBPARTITION s0 
                DATA DIRECTORY = '/disk0/data' 
                INDEX DIRECTORY = '/disk0/idx',
            SUBPARTITION s1 
                DATA DIRECTORY = '/disk1/data' 
                INDEX DIRECTORY = '/disk1/idx'
        ),
        PARTITION p1 VALUES LESS THAN (2000)
        (
            SUBPARTITION s0 
                DATA DIRECTORY = '/disk2/data' 
                INDEX DIRECTORY = '/disk2/idx',
            SUBPARTITION s1 
                DATA DIRECTORY = '/disk3/data' 
                INDEX DIRECTORY = '/disk3/idx'
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE
        (
            SUBPARTITION s0 
                DATA DIRECTORY = '/disk4/data' 
                INDEX DIRECTORY = '/disk4/idx',
            SUBPARTITION s1 
                DATA DIRECTORY = '/disk5/data' 
                INDEX DIRECTORY = '/disk5/idx'
        )
    )ï¼›

在这个例å­ä¸­ï¼Œæ¯ä¸ªRANGE分区的数æ®å’Œç´¢å¼•éƒ½ä½¿ç”¨ä¸€ä¸ªå•ç‹¬çš„ç£ç›˜ã€‚还å¯èƒ½æœ‰è®¸å¤šå…¶ä»–çš„å˜åŒ–;下é¢æ˜¯å¦å¤–一个å¯èƒ½çš„例å­ï¼š

CREATE TABLE ts (id INT, purchased DATE)
    PARTITION BY RANGE(YEAR(purchased))
    SUBPARTITION BY HASH(TO_DAYS(purchased))
    (
        PARTITION p0 VALUES LESS THAN (1990)
        (
            SUBPARTITION s0a 
                DATA DIRECTORY = '/disk0' 
                INDEX DIRECTORY = '/disk1',
            SUBPARTITION s0b 
                DATA DIRECTORY = '/disk2' 
                INDEX DIRECTORY = '/disk3'
        ),
        PARTITION p1 VALUES LESS THAN (2000)
        (
            SUBPARTITION s1a 
                DATA DIRECTORY = '/disk4/data' 
                INDEX DIRECTORY = '/disk4/idx',
            SUBPARTITION s1b 
                DATA DIRECTORY = '/disk5/data' 
                INDEX DIRECTORY = '/disk5/idx'
        ),
        PARTITION p2 VALUES LESS THAN MAXVALUE
        (
            SUBPARTITION s2a,
            SUBPARTITION s2b
        )
    )ï¼›

在这个例å­ä¸­ï¼Œå­˜å‚¨çš„分é…如下:

·         购买日期在1990å¹´å‰çš„记录å äº†å¤§é‡çš„存储空间,所以把它分为了四个部分进行存储,组æˆp0分区的两个å­åˆ†åŒºï¼ˆs0a å’Œs0b)的数æ®å’Œç´¢å¼•éƒ½åˆ†åˆ«ç”¨ä¸€ä¸ªå•ç‹¬çš„ç£ç›˜è¿›è¡Œå­˜å‚¨ã€‚æ¢å¥è¯è¯´ï¼š

o        å­åˆ†åŒºs0a çš„æ•°æ®ä¿å­˜åœ¨ç£ç›˜/disk0中。

o        å­åˆ†åŒºs0a 的索引ä¿å­˜åœ¨ç£ç›˜/disk1中。

o        å­åˆ†åŒºs0b çš„æ•°æ®ä¿å­˜åœ¨ç£ç›˜/disk2中。

o        å­åˆ†åŒºs0b 的索引ä¿å­˜åœ¨ç£ç›˜/disk3中。

·         ä¿å­˜è´­ä¹°æ—¥æœŸä»Ž1990年到1999年间的记录(分区p1)ä¸éœ€è¦ä¿å­˜è´­ä¹°æ—¥æœŸåœ¨1990年之å‰çš„记录那么大的存储空间。这些记录分在2个ç£ç›˜ï¼ˆ/disk4å’Œ/disk5)上ä¿å­˜ï¼Œè€Œä¸æ˜¯4个ç£ç›˜ï¼š

o        属于分区p1的第一个å­åˆ†åŒºï¼ˆs1a)的数æ®å’Œç´¢å¼•ä¿å­˜åœ¨ç£ç›˜/disk4上 — 其中数æ®ä¿å­˜åœ¨è·¯å¾„/disk4/data下,索引ä¿å­˜åœ¨/disk4/idx下。

o        属于分区p1的第二个å­åˆ†åŒºï¼ˆs1b)的数æ®å’Œç´¢å¼•ä¿å­˜åœ¨ç£ç›˜/disk5上 — 其中数æ®ä¿å­˜åœ¨è·¯å¾„/disk5/data下,索引ä¿å­˜åœ¨/disk5/idx下。

·         ä¿å­˜è´­ä¹°æ—¥æœŸä»Ž2000年到现在的记录(分区p2)ä¸éœ€è¦å‰é¢ä¸¤ä¸ªRANGE分区那么大的空间。当å‰ï¼Œåœ¨é»˜è®¤çš„ä½ç½®èƒ½å¤Ÿè¶³å¤Ÿä¿å­˜æ‰€æœ‰è¿™äº›è®°å½•ã€‚

å°†æ¥ï¼Œå¦‚果从2000年开始åŽåå¹´è´­ä¹°çš„æ•°é‡å·²ç»è¾¾åˆ°äº†é»˜è®¤çš„ä½ç½®ä¸èƒ½å¤Ÿæ供足够的ä¿å­˜ç©ºé—´æ—¶ï¼Œç›¸åº”的记录(行)å¯ä»¥é€šè¿‡ä½¿ç”¨â€œALTER TABLE ... REORGANIZE PARTITIONâ€è¯­å¥ç§»åŠ¨åˆ°å…¶ä»–çš„ä½ç½®ã€‚关于如何实现的说明,请å‚è§18.3节,“分区管ç†â€ 。

18.2.6. MySQL分区处ç†NULL值的方å¼

MySQL 中的分区在ç¦æ­¢ç©ºå€¼ï¼ˆNULL)上没有进行处ç†ï¼Œæ— è®ºå®ƒæ˜¯ä¸€ä¸ªåˆ—值还是一个用户定义表达å¼çš„值。一般而言,在这ç§æƒ…况下MySQL 把NULL视为0。如果你希望回é¿è¿™ç§åšæ³•ï¼Œä½ åº”该在设计表时ä¸å…许空值;最å¯èƒ½çš„方法是,通过声明列“NOT NULLâ€æ¥å®žçŽ°è¿™ä¸€ç‚¹ã€‚

在本节中,我们æ供了一些例å­ï¼Œæ¥è¯´æ˜Žå½“决定一个行应该ä¿å­˜åˆ°å“ªä¸ªåˆ†åŒºæ—¶ï¼ŒMySQL 是如何处ç†NULL值的。

如果æ’入一行到按照RANGE或LIST分区的表,该行用æ¥ç¡®å®šåˆ†åŒºçš„列值为NULL,分区将把该NULL值视为0。例如,考虑下é¢çš„两个表,表的创建和æ’入记录如下:

mysql> CREATE TABLE tnlist (
    ->     id INT,
    ->     name VARCHAR(5)
    -> )
    -> PARTITION BY LIST(id) (
    ->     PARTITION p1 VALUES IN (0),
    ->     PARTITION p2 VALUES IN (1)
    -> );
Query OK, 0 rows affected (0.09 sec)
 
mysql> CREATE TABLE tnrange (
    ->     id INT,
    ->     name VARCHAR(5)
    -> )
    -> PARTITION BY RANGE(id) (
    ->     PARTITION p1 VALUES LESS THAN (1),
    ->     PARTITION p2 VALUES LESS THAN MAXVALUE
    -> );
Query OK, 0 rows affected (0.09 sec)
 
mysql> INSERT INTO tnlist VALUES (NULL, 'bob');
Query OK, 1 row affected (0.00 sec)
 
mysql> INSERT INTO tnrange VALUES (NULL, 'jim');
Query OK, 1 row affected (0.00 sec)
 
mysql> SELECT * FROM tnlist;
+------+------+
| id   | name |
+------+------+
| NULL | bob  |
+------+------+
1 row in set (0.00 sec)
 
mysql> SELECT * FROM tnrange;
+------+------+
| id   | name |
+------+------+
| NULL | jim  |
+------+------+
1 row in set (0.00 sec)

在两个表中,id列没有声明为“NOT NULLâ€ï¼Œè¿™æ„味ç€å®ƒä»¬å…许Null值。å¯ä»¥é€šè¿‡åˆ é™¤è¿™äº›åˆ†åŒºï¼Œç„¶åŽé‡æ–°è¿è¡ŒSELECT 语å¥ï¼Œæ¥éªŒè¯è¿™äº›è¡Œè¢«ä¿å­˜åœ¨æ¯ä¸ªè¡¨çš„p1分区中:

mysql> ALTER TABLE tnlist DROP PARTITION p1;
Query OK, 0 rows affected (0.16 sec)
 
mysql> ALTER TABLE tnrange DROP PARTITION p1;
Query OK, 0 rows affected (0.16 sec)
 
mysql> SELECT * FROM tnlist;
Empty set (0.00 sec)
 
mysql> SELECT * FROM tnrange;
Empty set (0.00 sec)

在按HASHå’ŒKEY分区的情况下,任何产生NULL值的表达å¼éƒ½è§†åŒå¥½åƒå®ƒçš„返回值为0。我们å¯ä»¥é€šè¿‡å…ˆåˆ›å»ºä¸€ä¸ªæŒ‰HASH分区的表,然åŽæ’入一个包å«æœ‰é€‚当值的记录,å†æ£€æŸ¥å¯¹æ–‡ä»¶ç³»ç»Ÿçš„作用,æ¥éªŒè¯è¿™ä¸€ç‚¹ã€‚å‡å®šæœ‰ä½¿ç”¨ä¸‹é¢çš„语å¥åœ¨æµ‹è¯•æ•°æ®åº“中创建了一个表tnhash:

CREATE TABLE tnhash (
    id INT,
    name VARCHAR(5)
)
PARTITION BY HASH(id)
PARTITIONS 2ï¼›

å‡å¦‚Linux 上的MySQL 的一个RPM安装,这个语å¥åœ¨ç›®å½•/var/lib/mysql/test下创建了两个.MYD文件,这两个文件å¯ä»¥åœ¨bash shell中查看,结果如下:

/var/lib/mysql/test> ls *.MYD -l
-rw-rw----  1 mysql mysql 0 2005-11-04 18:41 tnhash_p0.MYD
-rw-rw----  1 mysql mysql 0 2005-11-04 18:41 tnhash_p1.MYD

注æ„:æ¯ä¸ªæ–‡ä»¶çš„大å°ä¸º0字节。现在在表tnhash 中æ’入一行id列值为NULL的行,然åŽéªŒè¯è¯¥è¡Œå·²ç»è¢«æ’入:

mysql> INSERT INTO tnhash VALUES (NULL, 'sam');
Query OK, 1 row affected (0.00 sec)
 
mysql> SELECT * FROM tnhash;
+------+------+
| id   | name |
+------+------+
| NULL | sam  |
+------+------+
1 row in set (0.01 sec)

回想一下,对于任æ„çš„æ•´æ•°N,NULL MOD N 的值总是等于NULL。这个结果在确定正确的分区方é¢è¢«è®¤ä¸ºæ˜¯0。回到系统shell(ä»ç„¶å‡å®šbash用于这个目的) ,通过å†æ¬¡åˆ—出数æ®æ–‡ä»¶ï¼Œå¯ä»¥çœ‹å‡ºå€¼è¢«æˆåŠŸåœ°æ’入到第一个分区(默认å称为p0)中:

var/lib/mysql/test> ls *.MYD -l
-rw-rw----  1 mysql mysql 20 2005-11-04 18:44 tnhash_p0.MYD
-rw-rw----  1 mysql mysql  0 2005-11-04 18:41 tnhash_p1.MYD

å¯ä»¥çœ‹å‡ºINSERT语å¥åªä¿®æ”¹äº†æ–‡ä»¶tnhash_p0.MYD,它在ç£ç›˜ä¸Šçš„尺寸增加了,而没有影å“其他的文件。

å‡å®šæœ‰ä¸‹é¢çš„一个表:

CREATE TABLE tndate (
    id INT,
    dt DATE
)
PARTITION BY RANGE( YEAR(dt) ) (
    PARTITION p0 VALUES LESS THAN (1990),
    PARTITION p1 VALUES LESS THAN (2000),
    PARTITION p2 VALUES LESS THAN MAXVALUE
)ï¼›

åƒå…¶ä»–çš„MySQL函数一样,YEAR(NULL)返回NULL值。一个dt列值为NULL的行,其分区表达å¼çš„计算结果被视为0,该行被æ’入到分区p0中。

18.3. åˆ†åŒºç®¡ç†

MySQL 5.1 æ供了许多修改分区表的方å¼ã€‚添加ã€åˆ é™¤ã€é‡æ–°å®šä¹‰ã€åˆå¹¶æˆ–拆分已ç»å­˜åœ¨çš„分区是å¯èƒ½çš„。所有这些æ“作都å¯ä»¥é€šè¿‡ä½¿ç”¨ALTER TABLE 命令的分区扩展æ¥å®žçŽ°(关于语法的定义,请å‚è§13.1.2节,“ALTER TABLE语法†)。也有获得分区表和分区信æ¯çš„æ–¹å¼ã€‚在本节,我们讨论下é¢è¿™äº›ä¸»é¢˜ï¼š

·         按RANGE或LIST分区的表的分区管ç†çš„有关信æ¯ï¼Œè¯·å‚è§18.3.1节,“RANGEå’ŒLIST分区的管ç†â€ã€‚

·         关于HASHå’ŒKEY分区管ç†çš„讨论,请å‚è§18.3.2节,“HASHå’ŒKEY分区的管ç†â€ã€‚

·         MySQL 5.1中æ供的ã€èŽ·å¾—关于分区表和分区信æ¯çš„机制的讨论,请å‚è§18.3.4节,“获å–关于分区的信æ¯â€ 。

·         关于执行分区维护æ“作的讨论,请å‚è§18.3.3节,“分区维护â€ã€‚

注释:在MySQL 5.1中,一个分区表的所有分区都必须有å­åˆ†åŒºåŒæ ·çš„å字,并且一旦表已ç»åˆ›å»ºï¼Œå†æ”¹å˜å­åˆ†åŒºæ˜¯ä¸å¯èƒ½çš„。

è¦ç‚¹ï¼šå½“å‰ï¼Œä»Ž5.1系列起建立的MySQL æœåŠ¡å™¨å°±æŠŠâ€œALTER TABLE ... PARTITION BY ...â€ä½œä¸ºæœ‰æ•ˆçš„语法,但是这个语å¥ç›®å‰è¿˜ä¸èµ·ä½œç”¨ã€‚我们期望MySQL 5.1达到生产状æ€æ—¶ï¼Œèƒ½å¤ŸæŒ‰ç…§ä¸‹é¢çš„æ述实现该语å¥çš„功能。

è¦æ”¹å˜ä¸€ä¸ªè¡¨çš„分区模å¼ï¼Œåªéœ€è¦ä½¿ç”¨å¸¦æœ‰ä¸€ä¸ªâ€œpartition_optionsâ€å­å¥çš„ALTER TABLE 的命令。这个å­å¥å’Œä¸Žåˆ›å»ºä¸€ä¸ªåˆ†åŒºè¡¨çš„CREATE TABLE命令一åŒä½¿ç”¨çš„å­å¥æœ‰ç›¸åŒçš„语法,并且总是以关键字PARTITION BY 开头。例如,å‡è®¾æœ‰ä¸€ä¸ªä½¿ç”¨ä¸‹é¢CREATE TABLE语å¥å»ºç«‹çš„按照RANGE分区的表:

CREATE TABLE trb3 (id INT, name VARCHAR(50), purchased DATE)
    PARTITION BY RANGE(YEAR(purchased))
    (
        PARTITION p0 VALUES LESS THAN (1990),
        PARTITION p1 VALUES LESS THAN (1995),
        PARTITION p2 VALUES LESS THAN (2000),
        PARTITION p3 VALUES LESS THAN (2005)
    )ï¼›

现在,è¦æŠŠè¿™ä¸ªè¡¨æŒ‰ç…§ä½¿ç”¨id列值作为键的基础,通过KEY分区把它é‡æ–°åˆ†æˆä¸¤ä¸ªåˆ†åŒºï¼Œå¯ä»¥ä½¿ç”¨ä¸‹é¢çš„语å¥ï¼š

ALTER TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2ï¼›

这和先删除这个表ã€ç„¶åŽä½¿ç”¨â€œCREATE TABLE trb3 PARTITION BY KEY(id) PARTITIONS 2ï¼›â€é‡æ–°åˆ›å»ºè¿™ä¸ªè¡¨å…·æœ‰åŒæ ·çš„效果。

18.3.1. RANGEå’ŒLIST分区的管ç†

关于如何添加和删除分区的处ç†ï¼ŒRANGEå’ŒLIST分区éžå¸¸ç›¸ä¼¼ã€‚基于这个原因,我们在本节讨论这两ç§åˆ†åŒºçš„管ç†ã€‚关于HASHå’ŒKEY分区管ç†çš„ä¿¡æ¯ï¼Œè¯·å‚è§18.3.2节,“HASHå’ŒKEY分区的管ç†â€ã€‚删除一个RANGE或LIST分区比增加一个分区è¦æ›´åŠ ç®€å•æ˜“懂,所以我们先讨论å‰è€…。

从一个按照RANGE或LIST分区的表中删除一个分区,å¯ä»¥ä½¿ç”¨å¸¦ä¸€ä¸ªDROP PARTITIONå­å¥çš„ALTER TABLE命令æ¥å®žçŽ°ã€‚这里有一个éžå¸¸åŸºæœ¬çš„例å­ï¼Œå‡è®¾å·²ç»ä½¿ç”¨ä¸‹é¢çš„CREATE TABLEå’ŒINSERT语å¥åˆ›å»ºäº†ä¸€ä¸ªæŒ‰ç…§RANGE分区的表,并且已ç»æ’入了10æ¡è®°å½•ï¼š

mysql> CREATE TABLE tr (id INT, name VARCHAR(50), purchased DATE)
    ->     PARTITION BY RANGE(YEAR(purchased))
    ->     (
    ->         PARTITION p0 VALUES LESS THAN (1990),
    ->         PARTITION p1 VALUES LESS THAN (1995),
    ->         PARTITION p2 VALUES LESS THAN (2000),
    ->         PARTITION p3 VALUES LESS THAN (2005)
    ->     );
Query OK, 0 rows affected (0.01 sec)
 
mysql> INSERT INTO tr VALUES
    ->     (1, 'desk organiser', '2003-10-15'),
    ->     (2, 'CD player', '1993-11-05'),
    ->     (3, 'TV set', '1996-03-10'),
    ->     (4, 'bookcase', '1982-01-10'),
    ->     (5, 'exercise bike', '2004-05-09'),
    ->     (6, 'sofa', '1987-06-05'),
    ->     (7, 'popcorn maker', '2001-11-22'),
    ->     (8, 'aquarium', '1992-08-04'),
    ->     (9, 'study desk', '1984-09-16'),
    ->     (10, 'lava lamp', '1998-12-25');
Query OK, 10 rows affected (0.01 sec)                  

å¯ä»¥é€šè¿‡ä½¿ç”¨ä¸‹é¢çš„命令查看那些记录已ç»æ’入到了分区p2中:

mysql> SELECT * FROM tr
    -> WHERE purchased BETWEEN '1995-01-01' AND '1999-12-31';
+------+-----------+------------+
| id   | name      | purchased  |
+------+-----------+------------+
|    3 | TV set    | 1996-03-10 |
|   10 | lava lamp | 1998-12-25 |
+------+-----------+------------+
2 rows in set (0.00 sec)

è¦åˆ é™¤å字为p2的分区,执行下é¢çš„命令:

mysql> ALTER TABLE tr DROP PARTITION p2;
Query OK, 0 rows affected (0.03 sec)

è®°ä½ä¸‹é¢ä¸€ç‚¹éžå¸¸é‡è¦ï¼šå½“删除了一个分区,也åŒæ—¶åˆ é™¤äº†è¯¥åˆ†åŒºä¸­æ‰€æœ‰çš„æ•°æ®ã€‚å¯ä»¥é€šè¿‡é‡æ–°è¿è¡Œå‰é¢çš„SELECT查询æ¥éªŒè¯è¿™ä¸€ç‚¹ï¼š

mysql> SELECT * FROM tr WHERE purchased 
    -> BETWEEN '1995-01-01' AND '1999-12-31';
Empty set (0.00 sec)

如果希望从所有分区删除所有的数æ®ï¼Œä½†æ˜¯åˆä¿ç•™è¡¨çš„定义和表的分区模å¼ï¼Œä½¿ç”¨TRUNCATE TABLE命令。(请å‚è§13.2.9节,“TRUNCATE语法â€ï¼‰ã€‚

如果希望改å˜è¡¨çš„分区而åˆä¸ä¸¢å¤±æ•°æ®ï¼Œä½¿ç”¨â€œALTER TABLE ... REORGANIZE PARTITIONâ€è¯­å¥ã€‚å‚è§ä¸‹é¢çš„内容,或者在13.1.2节,“ALTER TABLE语法†中å‚考关于REORGANIZE PARTITIONçš„ä¿¡æ¯ã€‚

如果现在执行一个SHOW CREATE TABLE命令,å¯ä»¥è§‚察到表的分区结构是如何被改å˜çš„:

mysql> SHOW CREATE TABLE tr\G
*************************** 1. row ***************************
       Table: tr
Create Table: CREATE TABLE `tr` (
  `id` int(11) default NULL,
  `name` varchar(50) default NULL,
  `purchased` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 
PARTITION BY RANGE (YEAR(purchased)) (
  PARTITION p0 VALUES LESS THAN (1990) ENGINE = MyISAM, 
  PARTITION p1 VALUES LESS THAN (1995) ENGINE = MyISAM, 
  PARTITION p3 VALUES LESS THAN (2005) ENGINE = MyISAM
)
1 row in set (0.01 sec)

如果æ’入购买日期列的值在'1995-01-01'å’Œ '2004-12-31'之间(å«ï¼‰çš„新行到已ç»ä¿®æ”¹åŽçš„表中时,这些行将被ä¿å­˜åœ¨åˆ†åŒºp3中。å¯ä»¥é€šè¿‡ä¸‹é¢çš„æ–¹å¼æ¥éªŒè¯è¿™ä¸€ç‚¹ï¼š

mysql> INSERT INTO tr VALUES (11, 'pencil holder', '1995-07-12');
Query OK, 1 row affected (0.00 sec)
 
mysql> SELECT * FROM tr WHERE purchased 
    -> BETWEEN '1995-01-01' AND '2004-12-31';
+------+----------------+------------+
| id   | name           | purchased  |
+------+----------------+------------+
|   11 | pencil holder  | 1995-07-12 |
|    1 | desk organiser | 2003-10-15 |
|    5 | exercise bike  | 2004-05-09 |
|    7 | popcorn maker  | 2001-11-22 |
+------+----------------+------------+
4 rows in set (0.00 sec)
 
mysql> ALTER TABLE tr DROP PARTITION p3;
Query OK, 0 rows affected (0.03 sec)
 
mysql> SELECT * FROM tr WHERE purchased 
    -> BETWEEN '1995-01-01' AND '2004-12-31';
Empty set (0.00 sec)

注æ„:由“ALTER TABLE ... DROP PARTITIONâ€è¯­å¥å¼•èµ·çš„ã€ä»Žè¡¨ä¸­åˆ é™¤çš„行数并没有被æœåŠ¡å™¨æŠ¥å‘Šå‡ºæ¥ï¼Œå°±å¥½åƒé€šè¿‡åŒç­‰çš„DELETE查询æ“作一样。

删除LIST分区使用和删除RANGE分区完全相åŒçš„“ALTER TABLE ... DROP PARTITIONâ€è¯­æ³•ã€‚但是,在对其åŽä½¿ç”¨è¿™ä¸ªè¡¨çš„å½±å“æ–¹é¢ï¼Œè¿˜æ˜¯æœ‰é‡å¤§çš„区别:在这个表中,å†ä¹Ÿä¸èƒ½æ’入这么一些行,这些行的列值包å«åœ¨å®šä¹‰å·²ç»åˆ é™¤äº†çš„分区的值列表中 (有关示例,请å‚è§18.2.2节,“LIST分区†)。

è¦å¢žåŠ ä¸€ä¸ªæ–°çš„RANGE或LIST分区到一个å‰é¢å·²ç»åˆ†åŒºäº†çš„表,使用“ALTER TABLE ... ADD PARTITIONâ€è¯­å¥ã€‚对于使用RANGE分区的表,å¯ä»¥ç”¨è¿™ä¸ªè¯­å¥æ·»åŠ æ–°çš„区间到已有分区的åºåˆ—çš„å‰é¢æˆ–åŽé¢ã€‚例如,å‡è®¾æœ‰ä¸€ä¸ªåŒ…å«ä½ æ‰€åœ¨ç»„织的全体æˆå‘˜æ•°æ®çš„分区表,该表的定义如下:

CREATE TABLE members (
    id INT, 
    fname VARCHAR(25),
    lname VARCHAR(25), 
    dob DATE
)
PARTITION BY RANGE(YEAR(dob)) (
    PARTITION p0 VALUES LESS THAN (1970),
    PARTITION p1 VALUES LESS THAN (1980),
    PARTITION p2 VALUES LESS THAN (1990)
);

进一步å‡è®¾æˆå‘˜çš„最å°å¹´çºªæ˜¯16å²ã€‚éšç€æ—¥åŽ†æŽ¥è¿‘2005年年底,你会认识到ä¸ä¹…å°†è¦æŽ¥çº³1990年(以åŠä»¥åŽå¹´ä»½ï¼‰å‡ºç”Ÿçš„æˆå‘˜ã€‚å¯ä»¥æŒ‰ç…§ä¸‹é¢çš„æ–¹å¼ï¼Œä¿®æ”¹æˆå‘˜è¡¨æ¥å®¹çº³å‡ºç”Ÿåœ¨1990ï¼1999年之间的æˆå‘˜ï¼š

ALTER TABLE ADD PARTITION (PARTITION p3 VALUES LESS THAN (2000));

è¦ç‚¹ï¼šå¯¹äºŽé€šè¿‡RANGE分区的表,åªå¯ä»¥ä½¿ç”¨ADD PARTITION添加新的分区到分区列表的高端。设法通过这ç§æ–¹å¼åœ¨çŽ°æœ‰åˆ†åŒºçš„å‰é¢æˆ–之间增加一个新的分区,将会导致下é¢çš„一个错误:

mysql> ALTER TABLE members ADD PARTITION (PARTITION p3 VALUES LESS THAN (1960));
错误1463 (HY000): 对æ¯ä¸ªåˆ†åŒºï¼ŒVALUES LESS THAN 值必须严格增长

采用一个类似的方å¼ï¼Œå¯ä»¥å¢žåŠ æ–°çš„分区到已ç»é€šè¿‡LIST分区的表。例如,å‡å®šæœ‰å¦‚下定义的一个表:

CREATE TABLE tt (
    id INT, 
    data INT
)
PARTITION BY LIST(data) (
    PARTITION p0 VALUES IN (5, 10, 15),
    PARTITION p1 VALUES IN (6, 12, 18)
)ï¼›

å¯ä»¥é€šè¿‡ä¸‹é¢çš„方法添加一个新的分区,用æ¥ä¿å­˜æ‹¥æœ‰æ•°æ®åˆ—值7,14å’Œ21的行:

ALTER TABLE tt ADD PARTITION (PARTITION p2 VALUES IN (7, 14, 21))ï¼›

注æ„:ä¸èƒ½æ·»åŠ è¿™æ ·ä¸€ä¸ªæ–°çš„LIST分区,该分区包å«æœ‰å·²ç»åŒ…å«åœ¨çŽ°æœ‰åˆ†åŒºå€¼åˆ—表中的任æ„值。如果试图这样åšï¼Œå°†ä¼šå¯¼è‡´é”™è¯¯ï¼š

mysql> ALTER TABLE tt ADD PARTITION (PARTITION np VALUES IN (4, 8, 12));
错误1465 (HY000): 在LIST分区中,åŒä¸€ä¸ªå¸¸æ•°çš„多次定义

因为带有数æ®åˆ—值12的任何行都已ç»åˆ†é…给了分区p1,所以ä¸èƒ½åœ¨è¡¨tt上å†åˆ›å»ºä¸€ä¸ªå…¶å€¼åˆ—表包括12的新分区。为了实现这一点,å¯ä»¥å…ˆåˆ é™¤åˆ†åŒºp1,添加分区np,然åŽä½¿ç”¨ä¿®æ­£åŽçš„定义添加一个新的分区p1。但是,正如我们å‰é¢è®¨è®ºè¿‡çš„,这将导致ä¿å­˜åœ¨åˆ†åŒºp1中的所有数æ®ä¸¢å¤±â€”—而这往往并ä¸æ˜¯ä½ æ‰€çœŸæ­£æƒ³è¦åšçš„。å¦å¤–一ç§è§£å†³æ–¹æ³•å¯èƒ½æ˜¯ï¼Œå»ºç«‹ä¸€ä¸ªå¸¦æœ‰æ–°åˆ†åŒºçš„表的副本,然åŽä½¿ç”¨â€œCREATE TABLE ... SELECT ...â€æŠŠæ•°æ®æ‹·è´åˆ°è¯¥æ–°è¡¨ä¸­ï¼Œç„¶åŽåˆ é™¤æ—§è¡¨ï¼Œé‡æ–°å‘½å新表,但是,当需è¦å¤„ç†å¤§é‡çš„æ•°æ®æ—¶ï¼Œè¿™å¯èƒ½æ˜¯éžå¸¸è€—时的。在需è¦é«˜å¯ç”¨æ€§çš„场åˆï¼Œè¿™ä¹Ÿå¯èƒ½æ˜¯ä¸å¯è¡Œçš„。

幸è¿åœ°æ˜¯ï¼ŒMySQL 的分区实现æ供了在ä¸ä¸¢å¤±æ•°æ®çš„æ¡ä»¶ä¸‹é‡æ–°å®šä¹‰åˆ†åŒºçš„æ–¹å¼ã€‚让我们首先看两个涉åŠåˆ°RANGE分区的简å•ä¾‹å­ã€‚回想一下现在定义如下的æˆå‘˜è¡¨ï¼š

mysql> SHOW CREATE TABLE members\G
*************************** 1. row ***************************
       Table: members
Create Table: CREATE TABLE `members` (
  `id` int(11) default NULL,
  `fname` varchar(25) default NULL,
  `lname` varchar(25) default NULL,
  `dob` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 
PARTITION BY RANGE (YEAR(dob)) (
  PARTITION p0 VALUES LESS THAN (1970) ENGINE = MyISAM, 
  PARTITION p1 VALUES LESS THAN (1980) ENGINE = MyISAM, 
  PARTITION p2 VALUES LESS THAN (1990) ENGINE = MyISAM.
  PARTITION p3 VALUES LESS THAN (2000) ENGINE = MyISAM
)

å‡å®šæƒ³è¦æŠŠè¡¨ç¤ºå‡ºç”Ÿåœ¨1960å¹´å‰æˆå‘˜çš„所有行移入到一个分开的分区中。正如我们å‰é¢çœ‹åˆ°çš„,ä¸èƒ½é€šè¿‡ä½¿ç”¨â€œALTER TABLE ... ADD PARTITIONâ€æ¥å®žçŽ°è¿™ä¸€ç‚¹ã€‚但是,è¦å®žçŽ°è¿™ä¸€ç‚¹ï¼Œå¯ä»¥ä½¿ç”¨ALTER TABLE上的å¦å¤–一个与分区有关的扩展,具体实现如下:

ALTER TABLE members REORGANIZE PARTITION p0 INTO (
    PARTITION s0 VALUES LESS THAN (1960),
    PARTITION s1 VALUES LESS THAN (1970)
)ï¼›

实际上,这个命令把分区p0分æˆäº†ä¸¤ä¸ªæ–°çš„分区s0å’Œs1。åŒæ—¶ï¼Œå®ƒè¿˜æ ¹æ®åŒ…å«åœ¨ä¸¤ä¸ªâ€œPARTITION ... VALUES ...â€å­å¥ä¸­çš„规则,把ä¿å­˜åœ¨åˆ†åŒºp0中的数æ®ç§»å…¥åˆ°ä¸¤ä¸ªæ–°çš„分区中,所以分区s0中åªåŒ…å«YEAR(dob)å°äºŽ1960的那些行,s1中包å«é‚£äº›YEAR(dob)大于或等于1960但是å°äºŽ1970的行。

一个REORGANIZE PARTITION语å¥ä¹Ÿå¯ä»¥ç”¨æ¥åˆå¹¶ç›¸é‚»çš„分区。å¯ä»¥ä½¿ç”¨å¦‚下的语å¥æ¢å¤æˆå‘˜è¡¨åˆ°å®ƒä»¥å‰çš„分区:

ALTER TABLE members REORGANIZE PARTITION s0,s1 INTO (
    PARTITION p0 VALUES LESS THAN (1970)
)ï¼›

使用“REORGANIZE PARTITIONâ€æ‹†åˆ†æˆ–åˆå¹¶åˆ†åŒºï¼Œæ²¡æœ‰æ•°æ®ä¸¢å¤±ã€‚在执行上é¢çš„语å¥ä¸­ï¼ŒMySQL 把ä¿å­˜åœ¨åˆ†åŒºs0å’Œs1中的所有数æ®éƒ½ç§»åˆ°åˆ†åŒºp0中。

“REORGANIZE PARTITIONâ€çš„基本语法是:

ALTER TABLE tbl_name REORGANIZE PARTITION partition_list INTO (partition_definitions)ï¼›

其中,tbl_name 是分区表的å称,partition_list 是通过逗å·åˆ†å¼€çš„ã€ä¸€ä¸ªæˆ–多个将è¦è¢«æ”¹å˜çš„现有分区的列表。partition_definitions 是一个是通过逗å·åˆ†å¼€çš„ã€æ–°åˆ†åŒºå®šä¹‰çš„列表,它éµå¾ªä¸Žç”¨åœ¨â€œCREATE TABLEâ€ä¸­çš„partition_definitions 相åŒçš„规则 (请å‚è§13.1.5节,“CREATE TABLE语法â€)。应当注æ„到,在把多少个分区åˆå¹¶åˆ°ä¸€ä¸ªåˆ†åŒºæˆ–把一个分区拆分æˆå¤šå°‘个分区方é¢ï¼Œæ²¡æœ‰é™åˆ¶ã€‚例如,å¯ä»¥é‡æ–°ç»„织æˆå‘˜è¡¨çš„四个分区æˆä¸¤ä¸ªåˆ†åŒºï¼Œå…·ä½“实现如下:

ALTER TABLE members REORGANIZE PARTITION p0,p1,p2,p3 INTO (
    PARTITION m0 VALUES LESS THAN (1980),
    PARTITION m1 VALUES LESS THAN (2000)
)ï¼›

åŒæ ·ï¼Œå¯¹äºŽæŒ‰LIST分区的表,也å¯ä»¥ä½¿ç”¨REORGANIZE PARTITION。让我们回到那个问题,å³å¢žåŠ ä¸€ä¸ªæ–°çš„分区到已ç»æŒ‰ç…§LIST分区的表tt中,但是因为该新分区有一个值已ç»å­˜åœ¨äºŽçŽ°æœ‰åˆ†åŒºçš„值列表中,添加新的分区失败。我们å¯ä»¥é€šè¿‡å…ˆæ·»åŠ åªåŒ…å«éžå†²çªå€¼çš„分区,然åŽé‡æ–°ç»„织该新分区和现有的那个分区,以便ä¿å­˜åœ¨çŽ°æœ‰çš„那个分区中的值现在移到了新的分区中,æ¥å¤„ç†è¿™ä¸ªé—®é¢˜ï¼š

ALTER TABLE tt ADD PARTITION (PARTITION np VALUES IN (4, 8));
ALTER TABLE tt REORGANIZE PARTITION p1,np INTO (
    PARTITION p1 VALUES IN (6, 18),
    PARTITION np VALUES in (4, 8, 12)
)ï¼›

当使用“ALTER TABLE ... REORGANIZE PARTITIONâ€æ¥å¯¹å·²ç»æŒ‰ç…§RANGEå’ŒLIST分区表进行é‡æ–°åˆ†åŒºæ—¶ï¼Œä¸‹é¢æ˜¯ä¸€äº›è¦è®°ä½çš„关键点:

·         用æ¥ç¡®å®šæ–°åˆ†åŒºæ¨¡å¼çš„PARTITIONå­å¥ä½¿ç”¨ä¸Žç”¨åœ¨CREATE TABLE中确定分区模å¼çš„PARTITIONå­å¥ç›¸åŒçš„规则。

最é‡è¦çš„是,应该记ä½ï¼šæ–°åˆ†åŒºæ¨¡å¼ä¸èƒ½æœ‰ä»»ä½•é‡å çš„区间(适用于按照RANGE分区的表)或值集åˆï¼ˆé€‚用于é‡æ–°ç»„织按照LIST分区的表)。

·         partition_definitions 列表中分区的åˆé›†åº”该与在partition_list 中命å分区的åˆé›†å æœ‰ç›¸åŒçš„区间或值集åˆã€‚

例如,在本节中用作例å­çš„æˆå‘˜è¡¨ä¸­ï¼Œåˆ†åŒºp1å’Œp2总共覆盖了1980到1999的这些年。因此,对这两个分区的é‡æ–°ç»„织都应该覆盖相åŒèŒƒå›´çš„年份。

·         对于按照RANGE分区的表,åªèƒ½é‡æ–°ç»„织相邻的分区;ä¸èƒ½è·³è¿‡RANGE分区。

例如,ä¸èƒ½ä½¿ç”¨ä»¥â€œALTER TABLE members REORGANIZE PARTITION p0,p2 INTO ...â€å¼€å¤´çš„语å¥ï¼Œæ¥é‡æ–°ç»„织本节中用作例å­çš„æˆå‘˜è¡¨ã€‚因为,p0覆盖了1970年以å‰çš„年份,而p2覆盖了从1990到1999(包括1990å’Œ1999)之间的年份,因而这两个分区ä¸æ˜¯ç›¸é‚»çš„分区。

·         ä¸èƒ½ä½¿ç”¨REORGANIZE PARTITIONæ¥æ”¹å˜è¡¨çš„分区类型;也就是说,例如,ä¸èƒ½æŠŠRANGE分区å˜ä¸ºHASH分区,å之亦然。也ä¸èƒ½ä½¿ç”¨è¯¥å‘½ä»¤æ¥æ”¹å˜åˆ†åŒºè¡¨è¾¾å¼æˆ–列。如果想在ä¸åˆ é™¤å’Œé‡å»ºè¡¨çš„æ¡ä»¶ä¸‹å®žçŽ°è¿™ä¸¤ä¸ªä»»åŠ¡ï¼Œå¯ä»¥ä½¿ç”¨â€œALTER TABLE ... PARTITION BY ....â€ï¼Œä¾‹å¦‚:

·                ALTER TABLE members 
·                    PARTITION BY HASH(YEAR(dob))
·                    PARTITIONS 8ï¼›

注释:在MySQL 5.1å‘布å‰çš„版本中,“ALTER TABLE ... PARTITION BY ...â€è¿˜æ²¡æœ‰å®žçŽ°ã€‚作为替代,è¦ä¹ˆä½¿ç”¨å…ˆåˆ é™¤è¡¨ï¼Œç„¶åŽä½¿ç”¨æƒ³è¦çš„分区é‡å»ºè¡¨ï¼Œæˆ–者——如果需è¦ä¿ç•™å·²ç»å­˜å‚¨åœ¨è¡¨ä¸­çš„æ•°æ®â€”—å¯ä»¥ä½¿ç”¨â€œCREATE TABLE ... SELECT ...â€æ¥åˆ›å»ºæ–°çš„表,然åŽä»Žæ—§è¡¨ä¸­æŠŠæ•°æ®æ‹·è´åˆ°æ–°è¡¨ä¸­ï¼Œå†åˆ é™¤æ—§è¡¨ï¼Œå¦‚有必è¦ï¼Œæœ€åŽé‡æ–°å‘½å新表。

18.3.2. HASHå’ŒKEY分区的管ç†

在改å˜åˆ†åŒºè®¾ç½®æ–¹é¢ï¼ŒæŒ‰ç…§HASH分区或KEY分区的表彼此éžå¸¸ç›¸ä¼¼ï¼Œä½†æ˜¯å®ƒä»¬åˆä¸ŽæŒ‰ç…§RANGE或LIST分区的表在很多方é¢æœ‰å·®åˆ«ã€‚所以,本节åªè®¨è®ºæŒ‰ç…§HASH或KEY分区表的修改。关于添加和删除按照RANGE或LIST进行分区的表的分区的讨论,å‚è§18.3.1节,“RANGEå’ŒLIST分区的管ç†â€ã€‚

ä¸èƒ½ä½¿ç”¨ä¸Žä»ŽæŒ‰ç…§RANGE或LIST分区的表中删除分区相åŒçš„æ–¹å¼ï¼Œæ¥ä»ŽHASH或KEY分区的表中删除分区。但是,å¯ä»¥ä½¿ç”¨â€œALTER TABLE ... COALESCE PARTITIONâ€å‘½ä»¤æ¥åˆå¹¶HASH或KEY分区。例如,å‡å®šæœ‰ä¸€ä¸ªåŒ…å«é¡¾å®¢ä¿¡æ¯æ•°æ®çš„表,它被分æˆäº†12个分区。该顾客表的定义如下:

CREATE TABLE clients (
    id INT,
    fname VARCHAR(30),
    lname VARCHAR(30),
    signed DATE
)
PARTITION BY HASH( MONTH(signed) )
PARTITIONS 12ï¼›

è¦å‡å°‘分区的数é‡ä»Ž12到6,执行下é¢çš„ALTER TABLE命令:

mysql> ALTER TABLE clients COALESCE PARTITION 6ï¼›
Query OK, 0 rows affected (0.02 sec)

对于按照HASH,KEY,LINEAR HASH,或LINEAR KEY分区的表, COALESCE能起到åŒæ ·çš„作用。下é¢æ˜¯ä¸€ä¸ªç±»ä¼¼äºŽå‰é¢ä¾‹å­çš„å¦å¤–一个例å­ï¼Œå®ƒä»¬çš„区别åªæ˜¯åœ¨äºŽè¡¨æ˜¯æŒ‰ç…§LINEAR KEY 进行分区:

mysql> CREATE TABLE clients_lk (
    ->     id INT,
    ->     fname VARCHAR(30),
    ->     lname VARCHAR(30),
    ->     signed DATE
    -> )
    -> PARTITION BY LINEAR KEY(signed)
    -> PARTITIONS 12ï¼›
Query OK, 0 rows affected (0.03 sec)
 
mysql> ALTER TABLE clients_lk COALESCE PARTITION 6ï¼›
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

COALESCEä¸èƒ½ç”¨æ¥å¢žåŠ åˆ†åŒºçš„æ•°é‡ï¼Œå¦‚果你å°è¯•è¿™ä¹ˆåšï¼Œç»“果会出现类似于下é¢çš„错误:

mysql> ALTER TABLE clients COALESCE PARTITION 18;
错误1478 (HY000): ä¸èƒ½ç§»åŠ¨æ‰€æœ‰åˆ†åŒºï¼Œä½¿ç”¨DROP TABLE代替

è¦å¢žåŠ é¡¾å®¢è¡¨çš„分区数é‡ä»Ž12到18,使用“ALTER TABLE ... ADD PARTITIONâ€,具体如下:

ALTER TABLE clients ADD PARTITION PARTITIONS 18ï¼›

注释:“ALTER TABLE ... REORGANIZE PARTITIONâ€ä¸èƒ½ç”¨äºŽæŒ‰ç…§HASH或HASH分区的表。

18.3.3. åˆ†åŒºç»´æŠ¤

注释:实际上,本节讨论的命令还没有在MySQL 5.1中实现, 在这里æ出的目的,是为了在5.1版投产å‰çš„å¼€å‘周期期间,引出æ¥è‡ªç”¨æˆ·æµ‹è¯•è¯¥è½¯ä»¶çš„å馈æ„è§ã€‚(æ¢å¥è¯è¯´ï¼Œå°±æ˜¯â€œè¯·ä¸è¦å馈这样的缺陷,说这些命令ä¸èµ·ä½œç”¨â€ï¼‰ã€‚éšç€MySQL5.1版开å‘的继续,这些信æ¯å¾ˆæœ‰å¯èƒ½å‘生å˜åŒ–。éšç€åˆ†åŒºåŠŸèƒ½çš„实现和æ高,我们将更新本节的内容。

MySQL 5.1中å¯ä»¥æ‰§è¡Œè®¸å¤šåˆ†åŒºç»´æŠ¤çš„任务。对于分区表,MySQLä¸æ”¯æŒå‘½ä»¤CHECK TABLE,OPTIMIZE TABLE,ANALYZE TABLE,或REPAIR TABLE。作为替代,å¯ä»¥ä½¿ç”¨ALTER TABLE 的许多扩展æ¥åœ¨ä¸€ä¸ªæˆ–多个分区上直接地执行这些æ“作,如下é¢åˆ—出的那样:

·         é‡å»ºåˆ†åŒº: 这和先删除ä¿å­˜åœ¨åˆ†åŒºä¸­çš„所有记录,然åŽé‡æ–°æ’入它们,具有åŒæ ·çš„效果。它å¯ç”¨äºŽæ•´ç†åˆ†åŒºç¢Žç‰‡ã€‚

示例:

ALTER TABLE t1 REBUILD PARTITION (p0, p1)ï¼›

·         优化分区:如果从分区中删除了大é‡çš„行,或者对一个带有å¯å˜é•¿åº¦çš„行(也就是说,有VARCHAR,BLOB,或TEXT类型的列)作了许多修改,å¯ä»¥ä½¿ç”¨â€œALTER TABLE ... OPTIMIZE PARTITIONâ€æ¥æ”¶å›žæ²¡æœ‰ä½¿ç”¨çš„空间,并整ç†åˆ†åŒºæ•°æ®æ–‡ä»¶çš„碎片。

示例:

ALTER TABLE t1 OPTIMIZE PARTITION (p0, p1)ï¼›

在一个给定的分区表上使用“OPTIMIZE PARTITIONâ€ç­‰åŒäºŽåœ¨é‚£ä¸ªåˆ†åŒºä¸Šè¿è¡ŒCHECK PARTITION,ANALYZE PARTITION,和REPAIR PARTITION。

·         分æžåˆ†åŒºï¼šè¯»å–并ä¿å­˜åˆ†åŒºçš„键分布。

示例:

ALTER TABLE t1 ANALYZE PARTITION (p3)ï¼›

·         修补分区: 修补被破å的分区。

示例:

ALTER TABLE t1 REPAIR PARTITION (p0,p1);

·         检查分区: å¯ä»¥ä½¿ç”¨å‡ ä¹Žä¸Žå¯¹éžåˆ†åŒºè¡¨ä½¿ç”¨CHECK TABLE 相åŒçš„æ–¹å¼æ£€æŸ¥åˆ†åŒºã€‚

示例:

ALTER TABLE trb3 CHECK PARTITION (p1)ï¼›

这个命令å¯ä»¥å‘Šè¯‰ä½ è¡¨t1的分区p1中的数æ®æˆ–索引是å¦å·²ç»è¢«ç ´å。如果å‘生了这ç§æƒ…况,使用“ALTER TABLE ... REPAIR PARTITIONâ€æ¥ä¿®è¡¥è¯¥åˆ†åŒºã€‚

还å¯ä»¥ä½¿ç”¨mysqlcheck或myisamchk 应用程åºï¼Œåœ¨å¯¹è¡¨è¿›è¡Œåˆ†åŒºæ—¶æ‰€äº§ç”Ÿçš„ã€å•ç‹¬çš„MYI文件上进行æ“作,æ¥å®Œæˆè¿™äº›ä»»åŠ¡ã€‚请å‚è§8.7节,“mysqlcheck:表维护和维修程åºâ€ã€‚(在pre-alphaç¼–ç ä¸­ï¼Œè¿™ä¸ªåŠŸèƒ½å·²ç»å¯ä»¥ä½¿ç”¨ï¼‰ã€‚

18.3.4. èŽ·å–关于分区的信æ¯

本节讨论获å–关于现有分区的信æ¯ã€‚这个功能ä»ç„¶å¤„于计划阶段,所以现阶段在这里æ述的,实际上是我们想è¦åœ¨MySQL 5.1中实现的一个概观。

如在本章中别处讨论的一样,在SHOW CREATE TABLE的输出中包å«äº†ç”¨äºŽåˆ›å»ºåˆ†åŒºè¡¨çš„PARTITION BYå­å¥ã€‚例如:

mysql> SHOW CREATE TABLE trb3\G
*************************** 1. row ***************************
       Table: trb3
Create Table: CREATE TABLE `trb3` (
  `id` int(11) default NULL,
  `name` varchar(50) default NULL,
  `purchased` date default NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 
PARTITION BY RANGE (YEAR(purchased)) (
  PARTITION p0 VALUES LESS THAN (1990) ENGINE = MyISAM, 
  PARTITION p1 VALUES LESS THAN (1995) ENGINE = MyISAM, 
  PARTITION p2 VALUES LESS THAN (2000) ENGINE = MyISAM, 
  PARTITION p3 VALUES LESS THAN (2005) ENGINE = MyISAM
)
1 row in set (0.00 sec)

注释:当å‰ï¼Œå¯¹äºŽæŒ‰HASH或KEY分区的表,PARTITIONSå­å¥å¹¶ä¸æ˜¾ç¤ºã€‚ (Bug #14327)

SHOW TABLE STATUS用于分区表,它的输出与用于éžåˆ†åŒºè¡¨çš„输出相åŒï¼Œé™¤äº†å¼•æ“Žï¼ˆEngine)列总是包å«'PARTITION'值。(关于这个命令的更多信æ¯ï¼Œå‚è§13.5.4.18节,“SHOW TABLE STATUS语法â€ï¼‰ã€‚è¦èŽ·å–å•ä¸ªåˆ†åŒºçš„状æ€ä¿¡æ¯ï¼Œæˆ‘们计划实现一个SHOW PARTITION STATUS命令(请å‚è§ä¸‹é¢)。

计划用于分区表的ã€ä¸¤ä¸ªé™„加的SHOW命令是:

·         SHOW PARTITIONS

这个命令预期其功能类似于SHOW TABLESå’ŒSHOW DATABASES,除了该命令将列出的是分区而ä¸æ˜¯è¡¨æˆ–æ•°æ®åº“。这个命令的输出å¯èƒ½åŒ…å«å•ä¸ªç§°ä¸ºPartitions_in_tbl_name 的列,其中tbl_name 是分区表的å字。对于SHOW TABLES命令而言,如果一旦选择了一个数æ®åº“,éšåŽè¯¥æ•°æ®åº“将作为SHOW TABLES命令的默认数æ®åº“。但是由于SHOW PARTITIONS命令ä¸å¯èƒ½ç”¨è¿™æ ·çš„æ–¹å¼æ¥â€œé€‰æ‹©â€ä¸€ä¸ªè¡¨ï¼Œå®ƒå¾ˆå¯èƒ½éœ€è¦ä½¿ç”¨FROMå­å¥ï¼Œä»¥ä¾¿MySQL知é“è¦æ˜¾ç¤ºçš„是哪个表的分区信æ¯ã€‚

·         SHOW PARTITION STATUS

这个命令将æ供关于一个或多个分区的详细状æ€ä¿¡æ¯ã€‚它的输出很å¯èƒ½åŒ…å«æœ‰ä¸ŽSHOW TABLE STATUS 的输出相åŒæˆ–类似的列,此外,还包括显示用于分区的数æ®å’Œç´¢å¼•è·¯å¾„的附加列。这个命令å¯èƒ½æ”¯æŒLIKEå’ŒFROMå­å¥ï¼Œè¿™æ ·ä½¿å¾—通过å字获得关于一个给定分区的信æ¯ï¼Œæˆ–者获得关于属于指定表或数æ®åº“的分区的信æ¯ï¼Œæˆä¸ºå¯èƒ½ã€‚

扩展INFORMATION_SCHEMA æ•°æ®åº“的计划也在进行中,以便æ供关于分区表和分区的信æ¯ã€‚这个计划当å‰è¿˜å¤„一个在éžå¸¸æ—©çš„阶段;éšç€è¡¥å……çš„ä¿¡æ¯å˜å¾—å¯ç”¨ï¼Œä»¥åŠä»»ä½•æ–°çš„ã€ä¸Žåˆ†åŒºæœ‰å…³çš„INFORMATION_SCHEMA扩展得以实现,我们将更新手册相关部分的内容。


这是MySQLå‚考手册的翻译版本,关于MySQLå‚考手册,请访问dev.mysql.com。原始å‚考手册为英文版,与英文版å‚考手册相比,本翻译版å¯èƒ½ä¸æ˜¯æœ€æ–°çš„。