`
zccst
  • 浏览: 3309921 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

通过分区(Partition)提升MySQL性能

阅读更多
通过分区(Partition)提升MySQL性能
               ——MySQL5.1新特性翻译系列
几年前,俺写过一篇题为“The Foundation of Excellent Performance”的文章(现在仍然可以在http://www.tdan.com/i016fe03.htm看到),俺对SQL语句是影响数据库驱动系统性能的第一要素的观点有点质疑。其实在那时我在文章中就坚信数据库的物理设计在对高级数据库的性能影响上远比其他因素重要。同时俺还给大家看了Oracle的研究,他们解释了为什么拙劣的物理设计是数据库停机(无论是有计划的还是没计划的)背后的主要原因。这么多年都过来啦(幸好没多少人朝俺扔砖头),俺的观点是改变了一些,但在这点上俺还是坚持DBA如果想要高性能的数据库就必须在数据库的物理设计上多思考的观点,这样才能减少响应时间使终端用户满意而不是引来骂声一片。(陈朋奕语:不要那么严肃,嘿嘿)
俺今天这么激动又想写文章的原因是MySQL5.1的发布带来了设计超强动力数据库的强有力的武器,任何MySQL的DBA都应该尽快学习并使用它。俺觉得如果能很好滴使用这个5.1版带来的新特性,DBA可以使自己管理的VLDB(不知道什么是VLDB?告诉你,是好大好大的数据库的意思,Very Large DB)或数据仓库奇迹般的获得巨大的性能提升。

什么是数据库分区?
数据库分区是一种物理数据库设计技术,DBA和数据库建模人员对其相当熟悉。虽然分区技术可以实现很多效果,但其主要目的是为了在特定的SQL操作中减少数据读写的总量以缩减响应时间。
分区主要有两种形式://这里一定要注意行和列的概念(row是行,column是列)

    水平分区(Horizontal Partitioning) 这种形式分区是对表的行进行分区,通过这样的方式不同分组里面的物理列分割的数据集得以组合,从而进行个体分割(单分区)或集体分割(1个或多个分区)。所有在表中定义的列在每个数据集中都能找到,所以表的特性依然得以保持。
    举个简单例子:一个包含十年发票记录的表可以被分区为十个不同的分区,每个分区包含的是其中一年的记录。(朋奕注:这里具体使用的分区方式我们后面再说,可以先说一点,一定要通过某个属性列来分割,譬如这里使用的列就是年份)
    垂直分区(Vertical Partitioning) 这种分区方式一般来说是通过对表的垂直划分来减少目标表的宽度,使某些特定的列被划分到特定的分区,每个分区都包含了其中的列所对应的行。
    举个简单例子:一个包含了大text和BLOB列的表,这些text和BLOB列又不经常被访问,这时候就要把这些不经常使用的text和BLOB了划分到另一个分区,在保证它们数据相关性的同时还能提高访问速度。

在数据库供应商开始在他们的数据库引擎中建立分区(主要是水平分区)时,DBA和建模者必须设计好表的物理分区结构,不要保存冗余的数据(不同表中同时都包含父表中的数据)或相互联结成一个逻辑父对象(通常是视图)。这种做法会使水平分区的大部分功能失效,有时候也会对垂直分区产生影响。


在MySQL 5.1中进行分区
     MySQL5.1中最激动人心的新特性应该就是对水平分区的支持了。这对MySQL的使用者来说确实是个好消息,而且她已经支持分区大部分模式:
         Range(范围) – 这种模式允许DBA将数据划分不同范围。例如DBA可以将一个表通过年份划分成三个分区,80年代(1980's)的数据,90年代(1990's)的数据以及任何在2000年(包括2000年)后的数据。
         Hash(哈希) – 这中模式允许DBA通过对表的一个或多个列的Hash Key进行计算,最后通过这个Hash码不同数值对应的数据区域进行分区,。例如DBA可以建立一个对表主键进行分区的表。
         Key(键值) – 上面Hash模式的一种延伸,这里的Hash Key是MySQL系统产生的。
         List(预定义列表) – 这种模式允许系统通过DBA定义的列表的值所对应的行数据进行分割。例如:DBA建立了一个横跨三个分区的表,分别根据2004年2005年和2006年值所对应的数据。
         Composite(复合模式) - 很神秘吧,哈哈,其实是以上模式的组合使用而已,就不解释了。举例:在初始化已经进行了Range范围分区的表上,我们可以对其中一个分区再进行hash哈希分区。
    分区带来的好处太多太多了,有多少?俺也不知道,自己猜去吧,要是觉得没有多少就别用,反正俺也不求你用。不过在这里俺强调两点好处:
性能的提升(Increased performance) - 在扫描操作中,如果MySQL的优化器知道哪个分区中才包含特定查询中需要的数据,它就能直接去扫描那些分区的数据,而不用浪费很多时间扫描不需要的地方了。需要举个例子?好啊,百万行的表划分为10个分区,每个分区就包含十万行数据,那么查询分区需要的时间仅仅是全表扫描的十分之一了,很明显的对比。同时对十万行的表建立索引的速度也会比百万行的快得多得多。如果你能把这些分区建立在不同的磁盘上,这时候的I/O读写速度就“不堪设想”(没用错词,真的太快了,理论上100倍的速度提升啊,这是多么快的响应速度啊,所以有点不堪设想了)了。
对数据管理的简化(Simplified data management) - 分区技术可以让DBA对数据的管理能力提升。通过优良的分区,DBA可以简化特定数据操作的执行方式。例如:DBA在对某些分区的内容进行删除的同时能保证余下的分区的数据完整性(这是跟对表的数据删除这种大动作做比较的)。
此外分区是由MySQL系统直接管理的,DBA不需要手工的去划分和维护。例如:这个例如没意思,不讲了,如果你是DBA,只要你划分了分区,以后你就不用管了就是了。

站在性能设计的观点上,俺们对以上的内容也是相当感兴趣滴。通过使用分区和对不同的SQL操作的匹配设计,数据库的性能一定能获得巨大提升。下面咱们一起用用这个MySQL 5.1的新功能看看。
下面所有的测试都在Dell Optiplex box with a Pentium 4 3.00GHz processor, 1GB of RAM机器上(炫耀啊……),Fedora Core 4和MySQL 5.1.6 alpha上运行通过。


如何进行实际分区
看看分区的实际效果吧。我们建立几个同样的MyISAM引擎的表,包含日期敏感的数据,但只对其中一个分区。分区的表(表名为part_tab)我们采用Range范围分区模式,通过年份进行分区:
mysql> CREATE TABLE part_tab
    ->      ( c1 int default NULL,
    -> c2 varchar(30) default NULL,
    -> c3 date default NULL
    ->
    ->      ) engine=myisam
    ->      PARTITION BY RANGE (year(c3)) (PARTITION p0 VALUES LESS THAN (1995),
    ->      PARTITION p1 VALUES LESS THAN (1996) , PARTITION p2 VALUES LESS THAN (1997) ,
    ->      PARTITION p3 VALUES LESS THAN (1998) , PARTITION p4 VALUES LESS THAN (1999) ,
    ->      PARTITION p5 VALUES LESS THAN (2000) , PARTITION p6 VALUES LESS THAN (2001) ,
    ->      PARTITION p7 VALUES LESS THAN (2002) , PARTITION p8 VALUES LESS THAN (2003) ,
    ->      PARTITION p9 VALUES LESS THAN (2004) , PARTITION p10 VALUES LESS THAN (2010),
    ->      PARTITION p11 VALUES LESS THAN MAXVALUE );
Query OK, 0 rows affected (0.00 sec)
注意到了这里的最后一行吗?这里把不属于前面年度划分的年份范围都包含了,这样才能保证数据不会出错,大家以后要记住啊,不然数据库无缘无故出错你就爽了。那下面我们建立没有分区的表(表名为no_part_tab):
mysql> create table no_part_tab
    -> (c1 int(11) default NULL,
    -> c2 varchar(30) default NULL,
    -> c3 date default NULL) engine=myisam;
Query OK, 0 rows affected (0.02 sec)
下面咱写一个存储过程(感谢Peter Gulutzan给的代码,如果大家需要Peter Gulutzan的存储过程教程的中文翻译也可以跟我要,chenpengyi◎gmail.com),它能向咱刚才建立的已分区的表中平均的向每个分区插入共8百万条不同的数据。填满后,咱就给没分区的克隆表中插入相同的数据:
mysql> delimiter //
mysql> CREATE PROCEDURE load_part_tab()
    -> begin
    -> declare v int default 0;
    ->          while v < 8000000
    -> do
    -> insert into part_tab
    -> values (v,'testing partitions',adddate('1995-01-01',(rand(v)*36520) mod 3652));
    -> set v = v + 1;
    -> end while;
    -> end
    -> //
Query OK, 0 rows affected (0.00 sec)
mysql> delimiter ;
mysql> call load_part_tab();
Query OK, 1 row affected (8 min 17.75 sec)
mysql> insert into no_part_tab select * from part_tab;
Query OK, 8000000 rows affected (51.59 sec)
Records: 8000000 Duplicates: 0 Warnings: 0

表都准备好了。咱开始对这两表中的数据进行简单的范围查询吧。先分区了的,后没分区的,跟着有执行过程解析(MySQL Explain命令解析器),可以看到MySQL做了什么:
mysql> select count(*) from no_part_tab where
    -> c3 > date '1995-01-01' and c3 < date '1995-12-31';
+----------+
| count(*) |
+----------+
|   795181 |
+----------+
1 row in set (38.30 sec)

mysql> select count(*) from part_tab where
    -> c3 > date '1995-01-01' and c3 < date '1995-12-31';
+----------+
| count(*) |
+----------+
|   795181 |
+----------+
1 row in set (3.88 sec)

mysql> explain select count(*) from no_part_tab where
    -> c3 > date '1995-01-01' and c3 < date '1995-12-31'\G
*************************** 1. row ***************************
           id: 1
select_type: SIMPLE
        table: no_part_tab
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 8000000
        Extra: Using where
1 row in set (0.00 sec)

mysql> explain partitions select count(*) from part_tab where
    -> c3 > date '1995-01-01' and c3 < date '1995-12-31'\G
*************************** 1. row ***************************
           id: 1
select_type: SIMPLE
        table: part_tab
   partitions: p1
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 798458
        Extra: Using where
1 row in set (0.00 sec)
从上面结果可以容易看出,设计恰当表分区能比非分区的减少90%的响应时间。而命令解析Explain程序也告诉我们在对已分区的表的查询过程中仅对第一个分区进行了扫描,其他都跳过了。
哔厉吧拉,说阿说……反正就是这个分区功能对DBA很有用拉,特别对VLDB和需要快速反应的系统。

对Vertical Partitioning的一些看法
虽然MySQL 5.1自动实现了水平分区,但在设计数据库的时候不要轻视垂直分区。虽然要手工去实现垂直分区,但在特定场合下你会收益不少的。例如在前面建立的表中,VARCHAR字段是你平常很少引用的,那么对它进行垂直分区会不会提升速度呢?咱们看看测试结果:
mysql> desc part_tab;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| c1    | int(11)     | YES |     | NULL    |       |
| c2    | varchar(30) | YES |     | NULL    |       |
| c3    | date        | YES |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.03 sec)

mysql> alter table part_tab drop column c2;
Query OK, 8000000 rows affected (42.20 sec)
Records: 8000000 Duplicates: 0 Warnings: 0

mysql> desc part_tab;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| c1    | int(11) | YES |     | NULL    |       |
| c3    | date    | YES |     | NULL    |       |
+-------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> select count(*) from part_tab where
    -> c3 > date '1995-01-01' and c3 < date '1995-12-31';
+----------+
| count(*) |
+----------+
|   795181 |
+----------+
1 row in set (0.34 sec)
在设计上去掉了VARCHAR字段后,不止是你,俺也发现查询响应速度上获得了另一个90%的时间节省。所以大家在设计表的时候,一定要考虑,表中的字段是否真正关联,又是否在你的查询中有用?

补充说明

这么简单的文章肯定不能说全MySQL 5.1 分区机制的所有好处和要点(虽然对自己写文章水平很有信心),下面就说几个感兴趣的:

    支持所有存储引擎(MyISAM, Archive, InnoDB, 等等)
    对分区的表支持索引,包括本地索引local indexes,对其进行的是一对一的视图镜像,假设一个表有十个分区,那么其本地索引也包含十个分区。
    关于分区的元数据Metadata的表可以在INFORMATION_SCHEMA数据库中找到,表名为PARTITIONS。
    All SHOW 命令支持返回分区表以及元数据的索引。
    对其操作的命令和实现的维护功能有(比对全表的操作还多):
        ADD PARTITION
        DROP PARTITION
        COALESCE PARTITION
        REORGANIZE PARTITION
        ANALYZE PARTITION
        CHECK PARTITION
        OPTIMIZE PARTITION
        REBUILD PARTITION
        REPAIR PARTITION

站在性能主导的观点上来说,MySQL 5.1的分区功能能给数据性能带来巨大的提升的同时减轻DBA的管理负担,如果分区合理的话。如果需要更多的资料可以去http://dev.mysql.com/doc/refman/5.1/en/partitioning.html或 http://forums.mysql.com/list.php?106获得相关资料。
关于MySQL分区的使用方法很快发布上来,这里有什么错误欢迎指出,或给我来信
——2006-05-05陈朋奕
分享到:
评论

相关推荐

    MYSQL 通过分区(Partition)提升MySQL性能

    ### MySQL通过分区(Partition)提升性能 在数据库管理和优化领域,分区是一种常用的技术手段,它可以帮助提高查询效率、简化数据管理以及改善系统整体性能。本文将深入探讨如何利用MySQL中的分区功能来提升数据库...

    mysql实现自动创建与删除分区

    MySQL数据库在大数据处理中扮演着重要角色,而分区技术是其优化查询性能的关键特性之一。本文将深入探讨如何实现MySQL的自动创建与删除分区,主要关注时间分区,并介绍相关存储过程和事件的设置。 首先,我们需要...

    创建mysql表分区的方法

    - 分区表的性能提升依赖于查询模式,如果查询不涉及分区列,可能无法充分利用分区优势。 - 分区表的维护成本可能会增加,特别是需要定期调整分区策略以适应数据增长。 综上所述,MySQL表分区是大数据场景下的有力...

    MySQL分区表自动创建及删除存储过程

    通过存储过程和事件调度器,可以实现分区的动态创建和删除,从而减轻数据库管理员的维护负担,同时保持数据库性能的高效。正确理解和使用这些资源,对于处理大规模数据的MySQL应用来说,将大大提高其可维护性和性能...

    MySQL 分区

    MySQL分区是一种数据库优化技术,它将大型表分成更小、更易...总的来说,MySQL分区是一个强大的工具,可以显著提升大规模数据库的性能。合理的设计和使用能够帮助开发者优化数据存储和查询,从而提高整个系统的效率。

    mysql表分区

    总的来说,MySQL表分区通过将一个大表的数据分散存储到多个物理位置,从而提高数据库的读写性能和管理效率。range、list和hash分区是MySQL提供的几种分区策略,每种策略根据不同的场景和需求进行选择和应用。在对...

    MySQL分区分表方案实践手册

    要检查MySQL是否支持分区功能,可以通过执行`SHOW VARIABLES LIKE '%partition%'`命令来查看。MySQL从5.1版本开始正式支持分区功能。 #### 二、MySQL分区类型 根据分区规则的不同,MySQL支持多种分区类型: - **...

    MySQL分区实战

    通过上述介绍可以看出,RANGE分区是MySQL数据库中一种非常实用且功能强大的特性,它不仅能够显著提高大型表的查询性能,还能够简化数据管理流程。理解并合理运用RANGE分区策略,对于提升数据库性能具有重要意义。

    MySql数据分区操作之新增分区操作

    首先,尝试直接通过`ALTER TABLE`语句添加分区到非分区表会导致错误,MySQL会返回`ERROR 1505 &lt;HY000&gt;: Partition management on a not partitioned table is not possible`。正确的方法是创建一个新的具有相同结构...

    mysql分区文档

    1. **性能提升**:通过分区,MySQL 只需扫描部分数据,减少了 I/O 操作,加快了查询速度。 2. **易于管理**:删除或更新大量数据时,可以针对特定分区操作,简化了数据维护工作。 3. **容错性**:即使一个分区出现...

    MySQL中创建数据表Range分区.pdf

    - 分区键应当是经常用于查询过滤的列,这样分区才能带来查询性能上的提升。 - 分区值必须是整数,因为MySQL Range分区不支持非整数类型的分区列。 - MAXVALUE是一个特殊值,表示此分区列的最大值。 - 分区数量不应...

    mysql如何进行分区-mysql分区有哪些方法.pdf

    MySQL 数据库是一个广泛使用的开源关系型数据库管理系统,尤其在 PHP Web 开发中极其...在确认 MySQL 服务器支持分区功能后(通过 `SHOW VARIABLES LIKE '%partition%'` 查询),可以进一步考虑分区的具体实现方式。

    (mysql面试题)MySQL中的分区表的概念及其作用及代码展示.txt

    例如,可以通过删除过时的分区来释放磁盘空间,或者将热点数据放置在高性能存储设备上以进一步优化性能。 3. **数据分布均衡**:通过合理设置分区策略,可以使数据在不同的分区中分布得更加均匀,避免出现数据“热点...

    mysql数据库表分区教程

    MySQL 数据库表分区教程 MySQL 数据库表分区是指将一个大表根据某些条件分割成多个小表,以提高数据库的可伸缩性、可管理性和效率。 MySQL 5.1 开始支持数据表分区。 什么是表分区 表分区是指将一个大表根据某些...

    mysql-分区

    MySQL 分区(Partition)是一种数据库优化技术,用于将大型表的数据分布到多个物理存储段,以提高查询性能和管理效率。分区通常适用于处理大量数据的表,尤其在数据仓库环境中非常常见。以下是对MySQL分区的一些关键...

    mysql如何进行分区-mysql分区有哪些方法.docx

    通过 `SHOW VARIABLES LIKE '%partition%'` 命令,可以检查 MySQL 服务器是否支持分区功能。 使用分区能有效管理和优化大数据量的表,但需要根据具体的应用场景和需求来选择合适的分区策略,同时也要考虑到对应用...

    mysql分区.pdf

    总之,MySQL分区是一种强大的数据管理技术,能够提升数据库的性能,并为数据的存储提供更灵活的策略,但需要根据实际情况来选择最合适的分区类型和分区键。在设计分区时,还需考虑分区键的选择和分区数量的确定,...

    mysql分库分表分区1

    表分区能够提升查询性能,因为分区可以限制查询的范围,减少了需要扫描的数据量。同时,它也简化了数据管理和维护,例如,可以通过直接删除或重建单个分区来快速清理过期数据。然而,分区并不总是适用所有情况,需要...

    mysql-partition-and-Index.rar_partition

    1. **性能提升**:通过将数据分布在不同的磁盘上,可以并行处理查询,提高数据读取速度。 2. **易于维护**:对大表进行插入、删除和更新操作更为高效,因为操作只影响特定的分区。 3. **空间管理**:更容易管理和...

Global site tag (gtag.js) - Google Analytics