How to make Spring Boot JPA support (Partition) in its Query - partitioning

I am working on a transaction table in MySQL, and according to some requirements I have to ALTER table (Transaction) and apply a partition on it (Year) wise, and (Sub-Partition) month-wise, and it worked successfully in MySQL workbench.
the query I applied is,
ALTER TABLE transaction
PARTITION BY RANGE (YEAR(TransactionDate))
SUBPARTITION BY KEY (month)
SUBPARTITIONS 12 (
partition p0 VALUES LESS THAN (2021),
partition p1 VALUES LESS THAN (2022),
partition p2 VALUES LESS THAN (2023),
partition p3 VALUES LESS THAN (2024),
partition p4 VALUES LESS THAN (2025),
partition p5 VALUES LESS THAN (2026),
partition p6 VALUES LESS THAN MAXVALUE
)
Now after applying this query in mySql DB ,
I want to write a JPA query in spring boot in eclipse which like,
SELECT Address,Number FROM Transaction **partition(p1)** where CustomerId =1;
as mentioned between (*) just to highlight the word (partition), this query is working fine in MySQL , but Spring boot is not supporting word partition any idea how should use partition in spring boot JPA query

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.

mysql partitioning does not work

I have a table with field which is action_time primary key and type is datetime
I try to break it on partitions
ALTER TABLE foo PARTITION BY RANGE (MONTH(action_time))
(
PARTITION p01 VALUES LESS THAN (02) ,
PARTITION p02 VALUES LESS THAN (03) ,
PARTITION p03 VALUES LESS THAN (04) ,
PARTITION p04 VALUES LESS THAN (05) ,
PARTITION p05 VALUES LESS THAN (06) ,
PARTITION p06 VALUES LESS THAN (07) ,
PARTITION p07 VALUES LESS THAN (08) ,
PARTITION p08 VALUES LESS THAN (09) ,
PARTITION p09 VALUES LESS THAN (10) ,
PARTITION p10 VALUES LESS THAN (11) ,
PARTITION p11 VALUES LESS THAN (12) ,
PARTITION p12 VALUES LESS THAN (13) ,
PARTITION pmaxval VALUES LESS THAN MAXVALUE
);
in phpmyadmin I see partitions with rows
but when I execute
explain partitions select * from foo where action_time between '2017-01-01 20:34:08' and '2017-01-21 20:34:08';
or
explain partitions select * from foo where action_time > '2017-01-01 20:34:08' && action_time < '2017-01-21 20:34:08'
it hits all partitions (p01,p02,p03,p04,p05,p06,p07,p08,p09,p10,p11,p12,pmaxval)
what I'm doing wrong ?
I also try this way the same result
ALTER TABLE foo
PARTITION BY RANGE( YEAR(action_time) )
SUBPARTITION BY HASH( MONTH(action_time) )
SUBPARTITIONS 12 (
PARTITION p2015 VALUES LESS THAN (2016),
PARTITION p2016 VALUES LESS THAN (2017),
PARTITION p2017 VALUES LESS THAN (2018),
PARTITION p2018 VALUES LESS THAN (2019),
PARTITION p2019 VALUES LESS THAN (2020),
PARTITION p2020 VALUES LESS THAN (2021),
PARTITION p2021 VALUES LESS THAN (2022),
PARTITION p2022 VALUES LESS THAN (2023),
PARTITION p2023 VALUES LESS THAN (2024),
PARTITION p2024 VALUES LESS THAN (2025),
PARTITION p2025 VALUES LESS THAN (2026),
PARTITION p2026 VALUES LESS THAN (2027),
PARTITION p2027 VALUES LESS THAN (2028),
PARTITION p2028 VALUES LESS THAN (2029),
PARTITION p2029 VALUES LESS THAN (2030),
PARTITION pmax VALUES LESS THAN MAXVALUE
);
I need to break the table by year and month for improve select time, when I'm selecting between dates it sholdn't search in whole table it should search in the relevant partitions. how can I do this?
You have found yet another reason why PARTITIONing is virtually useless.
Supposed you had specified BETWEEN '2015-11-05' AND '2017-02-02'. Which partitions would it need to hit? All of them.
Supposed you had specified BETWEEN '2015-11-05' AND '2016-02-02'. Which partitions would it need to hit? 4, but it is not smart enough to wrap around. So it will (I think) hit all.
There are a limited number of patterns (MONTH() is not one of them) where partitioning will "get it right".
To make BY RANGE( some date ) work, you are limited to BY RANGE(TO_DAYS(date)) (and a few others). But then you have to create a new partition every month (or however often). And, optionally, DROP the oldest partition.
Now for another reason why you plan is probably useless. What benefit to you expect to get from partitioning? Perhaps performance? Probably won't give you any performance benefit. Let's see your queries so I can explain why.
A simple
SELECT ...
WHERE date >= '...'
AND date < '...' + INTERVAL 20 DAY
will work just as fast with INDEX(date) as with partitioning. Possibly even faster.
If there is something else in the WHERE, then that changes everything.
My PARTITION blog
Why PARTITIONing does not speed up simple queries
Let's say you have a simple SELECT that has a very good index, such as you specify the exact value for the PRIMARY KEY. (This is called a "point query".)
Case 1: Non-partitioned table. Indexes use a BTree structure. Locating a specific record in a million rows requires drilling down the BTree, which will be about 3 levels deep. For a billion rows, it might be 5 levels.
Case 2: Partitioned table. Partitioning splits the table into multiple tables, each of which have indexes. Locating a specific row will first have to locate the particular partition (sub-table), then drill down the shallower BTree for that partition.
Think if it as (perhaps) removing one level from the BTree, but adding the extra effort of reaching for the partition. The performance difference is minuscule. And it is not clear whether you gain or lose. (Caching, data structures, etc, make this analysis complex.)
Conclusion: For Point Queries, Partitioning never helps, assuming you have a suitable index on the non-partitioned equivalent.
Your particular query is a simple "range" query: WHERE action_time BETWEEN ... AND ...
The optimal table structure (including partitioning and indexing) is
No partitions
INDEX(action_time)
Another note: If multiple partitions are involved, the SELECT will fetch rows (if any) from each partition (after pruning), put them together, and then might have to sort the results (depending on other clauses in the SELECT). Alas there is no parallelism in the execution of the query, so the partitioned variant is more involved, hence, probably slower.
MONTH() is not supported for partition pruning. Currently, only four functions are supported by MySQL 5.7/8.0.
In MySQL 8.0, partition pruning is supported for the TO_DAYS(),
TO_SECONDS(), YEAR(), and UNIX_TIMESTAMP() functions. See Chapter 5,
Partition Pruning, for more information.
You have to use TO_DAYS() instead. e.g.
ALTER TABLE foo PARTITION BY RANGE (TO_DAYS(action_time))
(
PARTITION p01 VALUES LESS THAN (TO_DAYS('2017-02-01')) ,
PARTITION p02 VALUES LESS THAN (TO_DAYS('2017-03-01')) ,
PARTITION pmaxval VALUES LESS THAN MAXVALUE
);

MySQL Partitioning Error - Error Code : 1486

MySQL throwing error while creating partitions on table.
Error Code : 1486
Constant, random or timezone-dependent expressions in (sub)partitioning function are not allowed.
I have tried following query :
alter table test.tbl1
partition by range(unix_timestamp(sys_time))
(
PARTITION p20151001 VALUES LESS THAN (unix_timestamp('2015-10-01')),
PARTITION p20151101 VALUES LESS THAN (unix_timestamp('2015-11-01')),
PARTITION p20151201 VALUES LESS THAN (unix_timestamp('2015-12-01')),
PARTITION p20160101 VALUES LESS THAN (unix_timestamp('2016-01-01')),
PARTITION p20160201 VALUES LESS THAN (unix_timestamp('2016-02-01')),
PARTITION p20160301 VALUES LESS THAN (unix_timestamp('2016-03-01'))
);
How can I round this problem.
Thanks in Advance
Reading here it may be possible that you are using MYSQL 5.1:
https://dev.mysql.com/tech-resources/articles/mysql_55_partitioning.html
Another pain point in MySQL 5.1 is the handling of date columns. You
can't use them directly, but you need to convert such columns using
either YEAR or TO_DAYS
If your column sys_time is a DATETIME, you dont need to specify the timestamp in order to partition it, you just need to do TO_DAYS, since you're not doing it by year:
alter table test.tbl1
partition by range (TO_DAYS(sys_time))
(
PARTITION p20151001 VALUES LESS THAN (TO_DAYS('2015-10-01')),
PARTITION p20151101 VALUES LESS THAN (TO_DAYS('2015-11-01')),
PARTITION p20151201 VALUES LESS THAN (TO_DAYS('2015-12-01')),
PARTITION p20160101 VALUES LESS THAN (TO_DAYS('2016-01-01')),
PARTITION p20160201 VALUES LESS THAN (TO_DAYS('2016-02-01')),
PARTITION p20160301 VALUES LESS THAN (TO_DAYS('2016-03-01'))
);
if sys_time is a TIMESTAMP then you dont need to convert your timestamp to a timestamp, I have taken that out of the range parameter:
alter table test.tbl1
partition by range(sys_time)
(
PARTITION p20151001 VALUES LESS THAN (unix_timestamp('2015-10-01')),
PARTITION p20151101 VALUES LESS THAN (unix_timestamp('2015-11-01')),
PARTITION p20151201 VALUES LESS THAN (unix_timestamp('2015-12-01')),
PARTITION p20160101 VALUES LESS THAN (unix_timestamp('2016-01-01')),
PARTITION p20160201 VALUES LESS THAN (unix_timestamp('2016-02-01')),
PARTITION p20160301 VALUES LESS THAN (unix_timestamp('2016-03-01'))
);

why explain partition shows first partition in every select query?

I have a table named edr on mysql 5.1.6* version. I have partitioned the table using alter -
ALTER TABLE edr PARTITION BY RANGE (TO_DAYS(eventDate))
(
PARTITION apr25 VALUES LESS THAN (TO_DAYS('2014-04-26')),
PARTITION apr26_30 VALUES LESS THAN (TO_DAYS('2014-05-01')),
PARTITION may01_05 VALUES LESS THAN (TO_DAYS('2014-05-06')),
PARTITION may06_10 VALUES LESS THAN (TO_DAYS('2014-05-11')),
PARTITION may11_15 VALUES LESS THAN (TO_DAYS('2014-05-16')),
PARTITION may16_20 VALUES LESS THAN (TO_DAYS('2014-05-21')),
PARTITION may21_25 VALUES LESS THAN (TO_DAYS('2014-05-26')),
PARTITION may26_31 VALUES LESS THAN (TO_DAYS('2014-06-01')),
PARTITION june01_05 VALUES LESS THAN (TO_DAYS('2014-06-06')),
PARTITION june06_10 VALUES LESS THAN (TO_DAYS('2014-06-11')),
PARTITION june11_15 VALUES LESS THAN (TO_DAYS('2014-06-16')));
now when I am running any query for example:
explain partitions select count(*) from edr where eventdate > '2014-05-21';
it gives me output for partitions as - apr25,may21_25, may26_31, jun01_05,jun_06_10,jun11_15.
Here in partition apr25 there is no record for such where condition.
please let me know is any thing wrong in above query or its a partition problem.
It is MySQL bug: explained here.
Try to create a first partition that contains values less than (0)
PARTITION unused VALUES LESS THAN (0);