What is the mistake in this MySQL partition query? - mysql

Please could you tell me the problem with this query:
ALTER TABLE
`phar_bills`
PARTITION BY RANGE COLUMNS (YEAR(bill_date))
(
PARTITION p0 VALUES LESS THAN (2014),
PARTITION p1 VALUES LESS THAN (2015),
PARTITION p2 VALUES LESS THAN (2016),
PARTITION p3 VALUES LESS THAN (2017),
PARTITION p4 VALUES LESS THAN (2018),
PARTITION p5 VALUES LESS THAN (2019),
PARTITION p6 VALUES LESS THAN (2020),
PARTITION p7 VALUES LESS THAN (2021),
PARTITION p8 VALUES LESS THAN (2022),
PARTITION p9 VALUES LESS THAN (2023),
PARTITION p10 VALUES LESS THAN (2024),
PARTITION p11 VALUES LESS THAN (2025),
PARTITION p12 VALUES LESS THAN (2026),
PARTITION p13 VALUES LESS THAN (2027),
PARTITION p14 VALUES LESS THAN (2028),
PARTITION p15 VALUES LESS THAN (2029),
PARTITION p16 VALUES LESS THAN (2030)
)
SUBPARTITION BY LIST COLUMNS(pharmacy_code)
(
PARTITION phar1 VALUES IN('1'),
PARTITION phar2 VALUES IN('2'),
PARTITION phar3 VALUES IN ('3')
)

What is the purpose of the word COLUMNS between RANGE and the partitioning expression?
BY RANGE COLUMNS (YEAR(bill_date))
^^^^^^^
What the plastic is that doing there? I don't believe that's valid syntax, but maybe you're running a newer version of MySQL.
YEAR(bill_date) is an expression, not the name of a column.
According to the MySQL 5.5 Reference Manual:
"RANGE COLUMNS does not accept expressions, only names of columns."
Reference: http://dev.mysql.com/doc/refman/5.5/en/partitioning-columns-range.html
But if that's not valid syntax, we'd fully expect MySQL to throw an error, most likely, a "#1064 You have an error in your syntax".
Aside from that, there are all sorts of other possible issues... but we'd expect most of those to also throw an actual MySQL error message. "partitioning not enabled", "storage engine doesn't support partitioning", "foreign keys not supported on partitioned tables", or some such.

Related

What is the difference between mysql drop partition and truncate partition

Can someone explain the difference between below commands?
ALTER TABLE A DROP PARTITION p0;
and
ALTER TABLE A TRUNCATE PARTITION p0;
In which scenarios should we use DROP/TRUNCATE partition?
Both throw the data away. And it is not 'transactional', so you cannot recover the data with a ROLLBACK.
DROP PARTITION also removes the partition from the list of partitions.
TRUNCATE PARTITION leaves the partition in place, but empty.
A common usage of DROP PARTITION is to remove "old" rows. Think of a table of of information that needs to be kept for only 90 days. Use PARTITION BY RANGE(TO_DAYS(...)) and have weekly partitions. Then, every week DROP the oldest and ADD a new partition. More discussion here.
I have not seen a need for TRUNCATE.
Be aware that there are very few use cases where you can get any benefit from PARTITIONing. So far, I have found uses only for PARTITION BY RANGE.
TRUNCATING a partition will be good choice when you have LIST partitions on the table.
It will remove all rows which are part of LIST partition but will not remove the partition entry from the table structure.
Take a scenario where you want to store credit card transactions/orders placed etc., in a MySQL table. Since the data volume is huge, you might want to partition it. Say you have partitioned the table based on the month of transaction.
PARTITION BY RANGE ( month(transactionDate))
(PARTITION p0 VALUES LESS THAN (2) ENGINE = InnoDB,
PARTITION p1 VALUES LESS THAN (3) ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN (4) ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN (5) ENGINE = InnoDB,
PARTITION p4 VALUES LESS THAN (6) ENGINE = InnoDB,
PARTITION p5 VALUES LESS THAN (7) ENGINE = InnoDB,
PARTITION p6 VALUES LESS THAN (8) ENGINE = InnoDB,
PARTITION p7 VALUES LESS THAN (9) ENGINE = InnoDB,
PARTITION p8 VALUES LESS THAN (10) ENGINE = InnoDB,
PARTITION p9 VALUES LESS THAN (11) ENGINE = InnoDB,
PARTITION p10 VALUES LESS THAN (12) ENGINE = InnoDB,
PARTITION p11 VALUES LESS THAN (13) ENGINE = InnoDB,
PARTITION p12 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ |
You can also do it week wise if your data volume is huge.
Now you have to clean the old data from time to time. This is where the difference between Drop and Truncate comes. The list of partitions you have initially is p0,p1...p12.
When you drop a partition p1, the list becomes p0,p2,p3,p4...p12. So effectively the data for both Feb and March would go into p2.
But when you do a truncate, p1 is still intact but the data is evicted. So the list remains p0,p1...p12.

Automation of mysql partitioning

I have searched lot about automation of mysql partitioning.
But unfortunately nothing matches to problem.
I want delete an older partitions which are not needed but at the same time add new upcoming data to partition.
What I can do here is every day drop an older partition and create new partitions with some automated functions of mysql such as MONTH(NOW()-interval 2 month) etc.
But what it will do is increase the cost of operation as every night I need recreate the partitions for new data.
I found that i can use partitioning by range but there are all hardcoded examples suggest's that i might need to do partitioning every time new data gets added.
Here is an example I found but not much similar to me :
ALTER TABLE t1 PARTITION BY
RANGE(TO_DAYS(FROM_UNIXTIME(transaction_date)))(
PARTITION JAN VALUES LESS THAN (TO_DAYS('2013-02-01')),
PARTITION FEB VALUES LESS THAN (TO_DAYS('2013-03-01')),
PARTITION MAR VALUES LESS THAN (TO_DAYS('2013-04-01')),
PARTITION APR VALUES LESS THAN (TO_DAYS('2013-05-01')),
PARTITION MAY VALUES LESS THAN (TO_DAYS('2013-06-01')),
PARTITION JUN VALUES LESS THAN (TO_DAYS('2013-07-01')),
PARTITION JUL VALUES LESS THAN (TO_DAYS('2013-08-01')),
PARTITION AUG VALUES LESS THAN (TO_DAYS('2013-09-01')),
PARTITION SEP VALUES LESS THAN (TO_DAYS('2013-10-01')),
PARTITION `OCT` VALUES LESS THAN (TO_DAYS('2013-11-01')),
PARTITION NOV VALUES LESS THAN (TO_DAYS('2013-12-01')),
PARTITION `DEC` VALUES LESS THAN (TO_DAYS('2014-01-01'))
);
Please suggest me a proper way to do it.
There is no fully automated way -- You need to write code.
But first, let's fix an issue. Have another partition:
PARTITION future VALUES LESS THAN (MAXVALUE)
This will come in handy if you accidentally fail to roll the partitions some night.
And how about a bug: Your table essentially never has a full 12 months of data. Just after a sliding of the partitions, you will have only 11 months. Is that OK? If not, keep 13 months, not 12.
Now for some code to do the work, plus perhaps some more tips: http://mysql.rjweb.org/doc.php/partitionmaint
You can do it like this. This will automatically store the data in the corresponding partitions. Regarding the automation of truncating them, I too am exploring the creation of scheduled events.
PARTITION BY RANGE ( month(creationDate))
(PARTITION p0 VALUES LESS THAN (2) ENGINE = InnoDB,
PARTITION p1 VALUES LESS THAN (3) ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN (4) ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN (5) ENGINE = InnoDB,
PARTITION p4 VALUES LESS THAN (6) ENGINE = InnoDB,
PARTITION p5 VALUES LESS THAN (7) ENGINE = InnoDB,
PARTITION p6 VALUES LESS THAN (8) ENGINE = InnoDB,
PARTITION p7 VALUES LESS THAN (9) ENGINE = InnoDB,
PARTITION p8 VALUES LESS THAN (10) ENGINE = InnoDB,
PARTITION p9 VALUES LESS THAN (11) ENGINE = InnoDB,
PARTITION p10 VALUES LESS THAN (12) ENGINE = InnoDB,
PARTITION p11 VALUES LESS THAN (13) ENGINE = InnoDB,
PARTITION p12 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */ |
This can be extended to creating partitions based on a week as well.

How can I partition using a BINARY column in MySQL?

I have so far only found the following very unelegant solution to creating a TABLE with a PARTITION on a BINARY column in MySQL (not part of primary key, so I can't use PARTITION BY KEY):
CREATE TABLE IF NOT EXISTS TestPartition (
uuid BINARY(16) NOT NULL
)
PARTITION BY RANGE COLUMNS(uuid) (
PARTITION p0 VALUES LESS THAN (X'10000000000000000000000000000000'),
PARTITION p1 VALUES LESS THAN (X'20000000000000000000000000000000'),
PARTITION p2 VALUES LESS THAN (X'30000000000000000000000000000000'),
PARTITION p3 VALUES LESS THAN (X'40000000000000000000000000000000'),
PARTITION p4 VALUES LESS THAN (X'50000000000000000000000000000000'),
PARTITION p5 VALUES LESS THAN (X'60000000000000000000000000000000'),
PARTITION p6 VALUES LESS THAN (X'70000000000000000000000000000000'),
PARTITION p7 VALUES LESS THAN (X'80000000000000000000000000000000'),
PARTITION p8 VALUES LESS THAN (X'90000000000000000000000000000000'),
PARTITION p9 VALUES LESS THAN (X'A0000000000000000000000000000000'),
PARTITION pA VALUES LESS THAN (X'B0000000000000000000000000000000'),
PARTITION pB VALUES LESS THAN (X'C0000000000000000000000000000000'),
PARTITION pC VALUES LESS THAN (X'D0000000000000000000000000000000'),
PARTITION pD VALUES LESS THAN (X'E0000000000000000000000000000000'),
PARTITION pE VALUES LESS THAN (X'F0000000000000000000000000000000'),
PARTITION pF VALUES LESS THAN (MAXVALUE)
);
Is there a better way to do this? This becomes unpleasant if I want more partitions.

MYSQL 5.5 partition table by first character 0-9a-zA-Z

I want to create a range partition on the first character in the character field. The field has hashtag values and is case sensitive 0-9a-zA-Z
I referred to the solution listed here.
This is what I execute:
CREATE TABLE tweetdbq4(hashtag CHAR(50), timestamp CHAR(14), tweetid BIGINT(18) UNSIGNED, userid INT(10) UNSIGNED) ENGINE=MYISAM
PARTITION BY RANGE COLUMNS(hashtag) (
PARTITION p0 VALUES LESS THAN ('a'),
PARTITION p1 VALUES LESS THAN ('b'),
PARTITION p2 VALUES LESS THAN ('c'),
PARTITION p3 VALUES LESS THAN ('d'),
PARTITION p4 VALUES LESS THAN ('e'),
PARTITION p5 VALUES LESS THAN ('f'),
PARTITION p6 VALUES LESS THAN ('g'),
PARTITION p7 VALUES LESS THAN ('h'),
PARTITION p8 VALUES LESS THAN ('i'),
PARTITION p9 VALUES LESS THAN ('j'),
PARTITION p10 VALUES LESS THAN ('k'),
PARTITION p11 VALUES LESS THAN ('l'),
PARTITION p12 VALUES LESS THAN ('m'),
PARTITION p13 VALUES LESS THAN ('n'),
PARTITION p14 VALUES LESS THAN ('o'),
PARTITION p15 VALUES LESS THAN ('p'),
PARTITION p16 VALUES LESS THAN ('q'),
PARTITION p17 VALUES LESS THAN ('r'),
PARTITION p18 VALUES LESS THAN ('s'),
PARTITION p19 VALUES LESS THAN ('t'),
PARTITION p20 VALUES LESS THAN ('u'),
PARTITION p21 VALUES LESS THAN ('v'),
PARTITION p22 VALUES LESS THAN ('w'),
PARTITION p23 VALUES LESS THAN ('x'),
PARTITION p24 VALUES LESS THAN ('y'),
PARTITION p25 VALUES LESS THAN ('z'),
PARTITION p26 VALUES LESS THAN ('A'),
PARTITION p27 VALUES LESS THAN ('B'),
PARTITION p28 VALUES LESS THAN ('C'),
PARTITION p29 VALUES LESS THAN ('D'),
PARTITION p30 VALUES LESS THAN ('E'),
PARTITION p31 VALUES LESS THAN ('F'),
PARTITION p32 VALUES LESS THAN ('G'),
PARTITION p33 VALUES LESS THAN ('H'),
PARTITION p34 VALUES LESS THAN ('I'),
PARTITION p35 VALUES LESS THAN ('J'),
PARTITION p36 VALUES LESS THAN ('K'),
PARTITION p37 VALUES LESS THAN ('L'),
PARTITION p38 VALUES LESS THAN ('M'),
PARTITION p39 VALUES LESS THAN ('N'),
PARTITION p40 VALUES LESS THAN ('O'),
PARTITION p41 VALUES LESS THAN ('P'),
PARTITION p42 VALUES LESS THAN ('Q'),
PARTITION p43 VALUES LESS THAN ('R'),
PARTITION p44 VALUES LESS THAN ('S'),
PARTITION p45 VALUES LESS THAN ('T'),
PARTITION p46 VALUES LESS THAN ('U'),
PARTITION p47 VALUES LESS THAN ('V'),
PARTITION p48 VALUES LESS THAN ('W'),
PARTITION p49 VALUES LESS THAN ('X'),
PARTITION p50 VALUES LESS THAN ('Y'),
PARTITION p51 VALUES LESS THAN ('Z'),
PARTITION p52 VALUES LESS THAN MAXVALUE
);
I get this error
ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition
By doing PARTITION p0 VALUES LESS THAN ('a') will it store partition on values starting from 0-9?
Can you tell me what am I doing wrong? Thanks!
It's because you're using range for partitioning, you have upper and lower case letters. You need to remove one, cause can not use same characters for range.
Plan A: Use a COLLATION for hashtag that ends in _bin, not _ci. "ci" stands for case insensitive. That is 'a' and 'A' are treated equal.
Plan B: Use only 26+1 partitions, not 52+1.
Why are you PARTITIONing? For performance? You probably won't get any performance boost. Let's see a query that you think will be sped up; I will explain why PARTITIONs will or (more likely) won't help.
Unrelated: Why is timestamp a CHAR(14) instead of a TIMESTAMP? CHAR(14) takes 14 or 42 bytes; timestamp takes 4 or 5. Smaller disk footprint leads to better performance.
Unrelated: Are hashtags exactly 50 characters? If not, use VARCHAR, not CHAR. If you argue that "FIXED" is better, I will explain that that is an old wives tale.
Unrelated: Do SHOW CREATE TABLE to see what CHARACTER SET you have. Then think about whether hashtags should be utf8 or not.

Changing MySQL range partition clause

I have a table created with range partitioning implemented. The clause is :
...partition by range (DAYOFMONTH(day))
(PARTITION p0 VALUES LESS THAN (1),
PARTITION p1 VALUES LESS THAN (2),
PARTITION p2 VALUES LESS THAN (3),
...
PARTITION p30 VALUES LESS THAN (31)
);
Now, I wish to change the partitioning condition to
.... partition by range (DAYOFMONTH(day) mod 31)
with the rest of individual partition definitions remaining the same. Is it possible to do so by any ALTER TABLE command or do I have to remove partitioning first and recreate partitions with the new condition?
I researched quite a lot about this but all information found was about reorganizing individual partitions.Thank you.
And you are saying following won't work for you ? I tried on version 5.6.10 successfully !
ALTER TABLE table_name
PARTITION BY RANGE( DAYOFMONTH(day) mod 31 ) (
PARTITION p0 VALUES LESS THAN (1),
PARTITION p1 VALUES LESS THAN (2),
PARTITION p2 VALUES LESS THAN (3),
PARTITION p3 VALUES LESS THAN (4),
...
PARTITION p30 VALUES LESS THAN (31)
);