MYSQL之表分區----按日期分區


MYSQL之表分區----按日期分區

錯誤的按日期分區例子
最直觀的方法,就是直接用年月日這種日期格式來進行常規的分區:
PLAIN TEXT
CODE:
  1.  
    mysql > create table rms (d date)
  2.  
    -> partition by range (d)
  3.  
    -> (partition p0 values less than ('1995-01-01'),
  4.  
    -> partition p1 VALUES LESS THAN ('2010-01-01'));


 
上面的例子中,就是直接用"Y-m-d"的格式來對一個table進行分區,可惜想當然往往不能奏效,會得到一個錯誤信息:
ERROR 1064 (42000): VALUES value must be of same type as partition function near '),
partition p1 VALUES LESS THAN ('2010-01-01'))' at line 3
上述分區方式沒有成功,而且明顯的不經濟,老練的DBA會用整型數值來進行分區:
PLAIN TEXT
CODE:
  1.  
    mysql > CREATE TABLE part_date1
  2.  
    -> ( c1 int default NULL,
  3.  
    -> c2 varchar(30) default NULL,
  4.  
    -> c3 date default NULL) engine=myisam
  5.  
    -> partition by range (cast(date_format(c3,'%Y%m%d') as signed))
  6.  
    -> (PARTITION p0 VALUES LESS THAN (19950101),
  7.  
    -> PARTITION p1 VALUES LESS THAN (19960101) ,
  8.  
    -> PARTITION p2 VALUES LESS THAN (19970101) ,
  9.  
    -> PARTITION p3 VALUES LESS THAN (19980101) ,
  10.  
    -> PARTITION p4 VALUES LESS THAN (19990101) ,
  11.  
    -> PARTITION p5 VALUES LESS THAN (20000101) ,
  12.  
    -> PARTITION p6 VALUES LESS THAN (20010101) ,
  13.  
    -> PARTITION p7 VALUES LESS THAN (20020101) ,
  14.  
    -> PARTITION p8 VALUES LESS THAN (20030101) ,
  15.  
    -> PARTITION p9 VALUES LESS THAN (20040101) ,
  16.  
    -> PARTITION p10 VALUES LESS THAN (20100101),
  17.  
    -> PARTITION p11 VALUES LESS THAN MAXVALUE );


Query OK, 0 rows affected (0.01 sec)
 
搞定?接着往下分析
PLAIN TEXT
CODE:
  1.  
    mysql > explain partitions
  2.  
    -> select count(*) from part_date1 where
  3.  
    -> c3> '1995-01-01' and c3 <'1995-12-31'\G
  4.  
    *************************** 1. row ***************************
  5.  
    id: 1
  6.  
    select_type: SIMPLE
  7.  
    table: part_date1
  8.  
    partitions: p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11
  9.  
    type: ALL
  10.  
    possible_keys: NULL
  11.  
    key: NULL
  12.  
    key_len: NULL
  13.  
    ref: NULL
  14.  
    rows: 8100000
  15.  
    Extra: Using where
  16.  
    1 row in set (0.00 sec)


 
萬惡的mysql居然對上面的sql使用全表掃描,而不是按照我們的日期分區分塊查詢。原文中解釋到MYSQL的優化器並不認這種日期形式的分區,花了大量的篇幅來引誘俺走上歧路,過分。
正確的日期分區例子
mysql優化器支持以下兩種內置的日期函數進行分區:
TO_DAYS()
YEAR()
看個例子:
PLAIN TEXT
CODE:
  1.  
    mysql > CREATE TABLE part_date3
  2.  
    -> ( c1 int default NULL,
  3.  
    -> c2 varchar(30) default NULL,
  4.  
    -> c3 date default NULL) engine=myisam
  5.  
    -> partition by range (to_days(c3))
  6.  
    -> (PARTITION p0 VALUES LESS THAN (to_days('1995-01-01')),
  7.  
    -> PARTITION p1 VALUES LESS THAN (to_days('1996-01-01')) ,
  8.  
    -> PARTITION p2 VALUES LESS THAN (to_days('1997-01-01')) ,
  9.  
    -> PARTITION p3 VALUES LESS THAN (to_days('1998-01-01')) ,
  10.  
    -> PARTITION p4 VALUES LESS THAN (to_days('1999-01-01')) ,
  11.  
    -> PARTITION p5 VALUES LESS THAN (to_days('2000-01-01')) ,
  12.  
    -> PARTITION p6 VALUES LESS THAN (to_days('2001-01-01')) ,
  13.  
    -> PARTITION p7 VALUES LESS THAN (to_days('2002-01-01')) ,
  14.  
    -> PARTITION p8 VALUES LESS THAN (to_days('2003-01-01')) ,
  15.  
    -> PARTITION p9 VALUES LESS THAN (to_days('2004-01-01')) ,
  16.  
    -> PARTITION p10 VALUES LESS THAN (to_days('2010-01-01')),
  17.  
    -> PARTITION p11 VALUES LESS THAN MAXVALUE );


Query OK, 0 rows affected (0.00 sec)
 
以to_days()函數分區成功,我們分析一下看看:
PLAIN TEXT
CODE:
  1.  
    mysql > explain partitions
  2.  
    -> select count(*) from part_date3 where
  3.  
    -> c3> date '1995-01-01' and c3 <date '1995-12-31'\G
  4.  
    *************************** 1. row ***************************
  5.  
    id: 1
  6.  
    select_type: SIMPLE
  7.  
    table: part_date3
  8.  
    partitions: p1
  9.  
    type: ALL
  10.  
    possible_keys: NULL
  11.  
    key: NULL
  12.  
    key_len: NULL
  13.  
    ref: NULL
  14.  
    rows: 808431
  15.  
    Extra: Using where
  16.  
    1 row in set (0.00 sec)


 
可以看到,mysql優化器這次不負眾望,僅僅在p1分區進行查詢。在這種情況下查詢,真的能夠帶來提升查詢效率么?下面分別對這次建立的part_date3和之前分區失敗的part_date1做一個查詢對比:
PLAIN TEXT
CODE:
  1.  
    mysql > select count(*) from part_date3 where
  2.  
    -> c3> date '1995-01-01' and c3 <date '1995-12-31';
  3.  
    +----------+
  4.  
    | count(*) |
  5.  
    +----------+
  6.  
    | 805114 |
  7.  
    +----------+
  8.  
    1 row in set (4.11 sec)
  9.  
     
  10.  
    mysql > select count(*) from part_date1 where
  11.  
    -> c3> date '1995-01-01' and c3 <date '1995-12-31';
  12.  
    +----------+
  13.  
    | count(*) |
  14.  
    +----------+
  15.  
    | 805114 |
  16.  
    +----------+
  17.  
    1 row in set (40.33 sec)


 
可以看到,分區正確的話query花費時間為4秒,而分區錯誤則花費時間40秒(相當於沒有分區),效率有90%的提升!所以我們千萬要正確的使用分區功能,分區后務必用explain驗證,這樣才能獲得真正的性能提升。


注意:
在mysql5.1中建立分區表的語句中,只能包含下列函數:
  1.  
    ABS()
  2.  
    CEILING() and FLOOR() (在使用這2個函數的建立分區表的前提是使用函數的分區鍵是INT類型),例如
  3.  
    mysql > CREATE TABLE t (c FLOAT) PARTITION BY LIST( FLOOR(c) )( -> PARTITION p0 VALUES IN (1,3,5), -> PARTITION p1 VALUES IN (2,4,6) -> );; ERROR 1491 (HY000): The PARTITION function returns the wrong type mysql> CREATE TABLE t (c int) PARTITION BY LIST( FLOOR(c) )( -> PARTITION p0 VALUES IN (1,3,5), -> PARTITION p1 VALUES IN (2,4,6) -> ); Query OK, 0 rows affected (0.01 sec)
  4.  
    DAY()
  5.  
    DAYOFMONTH()
  6.  
    DAYOFWEEK()
  7.  
    DAYOFYEAR()
  8.  
    DATEDIFF()
  9.  
    EXTRACT()
  10.  
    HOUR()
  11.  
    MICROSECOND()
  12.  
    MINUTE()
  13.  
    MOD()
  14.  
    MONTH()
  15.  
    QUARTER()
  16.  
    SECOND()
  17.  
    TIME_TO_SEC()
  18.  
    TO_DAYS()
  19.  
    WEEKDAY()
  20.  
    YEAR()
  21.  
    YEARWEEK()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM