所謂按天,不過是日期精確到天而已。
創(chuàng)新互聯(lián)專注于做網(wǎng)站、成都網(wǎng)站制作、網(wǎng)頁設(shè)計、網(wǎng)站制作、網(wǎng)站開發(fā)。公司秉持“客戶至上,用心服務(wù)”的宗旨,從客戶的利益和觀點出發(fā),讓客戶在網(wǎng)絡(luò)營銷中找到自己的駐足之地。尊重和關(guān)懷每一位客戶,用嚴(yán)謹(jǐn)?shù)膽B(tài)度對待客戶,用專業(yè)的服務(wù)創(chuàng)造價值,成為客戶值得信賴的朋友,為客戶解除后顧之憂。
錯誤的按日期分區(qū)例子
最直觀的方法,就是直接用年月日這種日期格式來進(jìn)行常規(guī)的分區(qū):
mysql??create?table?rms?(d?date)??
-??partition?by?range?(d)??
-?(partition?p0?values?less?than?('1995-01-01'),??
-??partition?p1?VALUES?LESS?THAN?('2010-01-01'));
上面的例子中,就是直接用"Y-m-d"的格式來對一個table進(jìn)行分區(qū),可惜想當(dāng)然往往不能奏效,會得到一個錯誤信息:
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
上述分區(qū)方式?jīng)]有成功,而且明顯的不經(jīng)濟(jì),老練的DBA會用整型數(shù)值來進(jìn)行分區(qū):
mysql?CREATE?TABLE?part_date1??
-??????(??c1?int?default?NULL,??
-??c2?varchar(30)?default?NULL,??
-??c3?date?default?NULL)?engine=myisam??
-??????partition?by?range?(cast(date_format(c3,'%Y%m%d')?as?signed))??
-?(PARTITION?p0?VALUES?LESS?THAN?(19950101),??
-?PARTITION?p1?VALUES?LESS?THAN?(19960101)?,??
-?PARTITION?p2?VALUES?LESS?THAN?(19970101)?,??
-?PARTITION?p3?VALUES?LESS?THAN?(19980101)?,??
-?PARTITION?p4?VALUES?LESS?THAN?(19990101)?,??
-?PARTITION?p5?VALUES?LESS?THAN?(20000101)?,??
-?PARTITION?p6?VALUES?LESS?THAN?(20010101)?,??
-?PARTITION?p7?VALUES?LESS?THAN?(20020101)?,??
-?PARTITION?p8?VALUES?LESS?THAN?(20030101)?,??
-?PARTITION?p9?VALUES?LESS?THAN?(20040101)?,??
-?PARTITION?p10?VALUES?LESS?THAN?(20100101),??
-?PARTITION?p11?VALUES?LESS?THAN?MAXVALUE?);
Query OK, 0 rows affected (0.01 sec)
搞定?接著往下分析
mysql?explain?partitions??
-?select?count(*)?from?part_date1?where??
-??????c3?'1995-01-01'?and?c3?'1995-12-31'\G??
***************************?1.?row?***************************??
id:?1??
select_type:?SIMPLE??
table:?part_date1??
partitions:?p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11??
type:?ALL??
possible_keys:?NULL??
key:?NULL??
key_len:?NULL??
ref:?NULL??
rows:?8100000??
Extra:?Using?where??
1?row?in?set?(0.00?sec)
萬惡的mysql居然對上面的sql使用全表掃描,而不是按照我們的日期分區(qū)分塊查詢。原文中解釋到MYSQL的優(yōu)化器并不認(rèn)這種日期形式的分區(qū),花了大量的篇幅來引誘俺走上歧路,過分。
正確的日期分區(qū)例子
mysql優(yōu)化器支持以下兩種內(nèi)置的日期函數(shù)進(jìn)行分區(qū):
TO_DAYS()
YEAR()
看個例子:
mysql?CREATE?TABLE?part_date3??
-??????(??c1?int?default?NULL,??
-??c2?varchar(30)?default?NULL,??
-??c3?date?default?NULL)?engine=myisam??
-??????partition?by?range?(to_days(c3))??
-?(PARTITION?p0?VALUES?LESS?THAN?(to_days('1995-01-01')),??
-?PARTITION?p1?VALUES?LESS?THAN?(to_days('1996-01-01'))?,??
-?PARTITION?p2?VALUES?LESS?THAN?(to_days('1997-01-01'))?,??
-?PARTITION?p3?VALUES?LESS?THAN?(to_days('1998-01-01'))?,??
-?PARTITION?p4?VALUES?LESS?THAN?(to_days('1999-01-01'))?,??
-?PARTITION?p5?VALUES?LESS?THAN?(to_days('2000-01-01'))?,??
-?PARTITION?p6?VALUES?LESS?THAN?(to_days('2001-01-01'))?,??
-?PARTITION?p7?VALUES?LESS?THAN?(to_days('2002-01-01'))?,??
-?PARTITION?p8?VALUES?LESS?THAN?(to_days('2003-01-01'))?,??
-?PARTITION?p9?VALUES?LESS?THAN?(to_days('2004-01-01'))?,??
-?PARTITION?p10?VALUES?LESS?THAN?(to_days('2010-01-01')),??
-?PARTITION?p11?VALUES?LESS?THAN?MAXVALUE?);
Query OK, 0 rows affected (0.00 sec)
以to_days()函數(shù)分區(qū)成功,我們分析一下看看:
mysql?explain?partitions??
-?select?count(*)?from?part_date3?where??
-??????c3?date?'1995-01-01'?and?c3?date?'1995-12-31'\G??
***************************?1.?row?***************************??
id:?1??
select_type:?SIMPLE??
table:?part_date3??
partitions:?p1??
type:?ALL??
possible_keys:?NULL??
key:?NULL??
key_len:?NULL??
ref:?NULL??
rows:?808431??
Extra:?Using?where??
1?row?in?set?(0.00?sec)
可以看到,mysql優(yōu)化器這次不負(fù)眾望,僅僅在p1分區(qū)進(jìn)行查詢。在這種情況下查詢,真的能夠帶來提升查詢效率么?下面分別對這次建立的part_date3和之前分區(qū)失敗的part_date1做一個查詢對比:
mysql?select?count(*)?from?part_date3?where??
-??????c3?date?'1995-01-01'?and?c3?date?'1995-12-31';??
+----------+??
|?count(*)?|??
+----------+??
|???805114?|??
+----------+??
1?row?in?set?(4.11?sec)??
mysql?select?count(*)?from?part_date1?where??
-??????c3?date?'1995-01-01'?and?c3?date?'1995-12-31';??
+----------+??
|?count(*)?|??
+----------+??
|???805114?|??
+----------+??
1?row?in?set?(40.33?sec)
可以看到,分區(qū)正確的話query花費時間為4秒,而分區(qū)錯誤則花費時間40秒(相當(dāng)于沒有分區(qū)),效率有90%的提升!所以我們千萬要正確的使用分區(qū)功能,分區(qū)后務(wù)必用explain驗證,這樣才能獲得真正的性能提升。
注意:
在mysql5.1中建立分區(qū)表的語句中,只能包含下列函數(shù):
ABS()
CEILING()?and?FLOOR()?(在使用這2個函數(shù)的建立分區(qū)表的前提是使用函數(shù)的分區(qū)鍵是INT類型),例如
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)??
DAY()??
DAYOFMONTH()??
DAYOFWEEK()??
DAYOFYEAR()??
DATEDIFF()??
EXTRACT()??
HOUR()??
MICROSECOND()??
MINUTE()??
MOD()??
MONTH()??
QUARTER()??
SECOND()??
TIME_TO_SEC()??
TO_DAYS()??
WEEKDAY()??
YEAR()??
YEARWEEK()
以下是創(chuàng)建一張測試表TEST并且按照時間CREATE_TIME創(chuàng)建RANGE分區(qū),并使用ID創(chuàng)建hash分區(qū),組成復(fù)合分區(qū)。
CREATE TABLE TEST (
CREATE_TIME DATETIME DEFAULT NULL, ID BIGINT(15) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8
PARTITION BY RANGE(TO_DAYS(CREATE_TIME)) PARTITIONS 7 SUBPARTITION BY HASH(ID) SUBPARTITIONS 16
(PARTITION P1710 VALUES LESS THAN (TO_DAYS ('2017-10-01'))
(SUBPARTITION P1710sp0 ,SUBPARTITION P1710sp1 ,
SUBPARTITION P1710sp2 ,SUBPARTITION P1710sp3 ,
SUBPARTITION P1710sp4 ,SUBPARTITION P1710sp5 ,
SUBPARTITION P1710sp6 ,SUBPARTITION P1710sp7 ,
SUBPARTITION P1710sp8 ,SUBPARTITION P1710sp9 ,
SUBPARTITION P1710sp10 ,SUBPARTITION P1710sp11 ,
SUBPARTITION P1710sp12 ,SUBPARTITION P1710sp13 ,
SUBPARTITION P1710sp14 ,SUBPARTITION P1710sp15 ),
PARTITION P1711 VALUES LESS THAN (TO_DAYS ('2017-11-01'))
(SUBPARTITION P1711sp0 ,SUBPARTITION P1711sp1 ,
SUBPARTITION P1711sp2 , SUBPARTITION P1711sp3 ,
SUBPARTITION P1711sp4 , SUBPARTITION P1711sp5 ,
SUBPARTITION P1711sp6 , SUBPARTITION P1711sp7 ,
SUBPARTITION P1711sp8 , SUBPARTITION P1711sp9 ,
SUBPARTITION P1711sp10 , SUBPARTITION P1711sp11 ,
SUBPARTITION P1711sp12 , SUBPARTITION P1711sp13 ,
SUBPARTITION P1711sp14 , SUBPARTITION P1711sp15 ),
用mysql的表分區(qū)功能(邏輯上還是一個表,對程序來說是透明的),通過分區(qū)函數(shù)可實現(xiàn)自動分表。如果想實現(xiàn)根據(jù)數(shù)據(jù)每月或每周動態(tài)的再分區(qū),可以寫一個存儲過程實現(xiàn)分區(qū)調(diào)整邏輯,最后寫一個mysql event(自動化作業(yè))按周期調(diào)用這個存儲過程就行了。