What is the difference between mysql drop partition and truncate partition - mysql

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.

Related

What is the best way to speed up collecting query from huge log table?

I have MySQL database log table that increasing daily with 5m of data
and I have issue with collecting data from that table to make some analyze counts.
I have listed the details of the problem as follows:
This is my log table:
CREATE TABLE `details` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`provider` VARCHAR(25) NULL COLLATE 'utf8mb4_unicode_ci',
`DLR_Status` VARCHAR(30) NULL COLLATE 'utf8mb4_unicode_ci',
`source` VARCHAR(30) NULL COLLATE 'utf8mb4_bin',
`Destination` VARCHAR(30) NULL COLLATE 'utf8mb4_unicode_ci',
`msg` VARCHAR(1000) NULL COLLATE 'utf8mb4_unicode_ci',
`timestamp` TIMESTAMP NULL,
`msg_timestamp` INT NOT NULL,
`created_at` TIMESTAMP NULL,
`updated_at` TIMESTAMP NULL,
PRIMARY KEY (`id`, `msg_timestamp`) USING BTREE
)
COLLATE='utf8mb4_unicode_ci'
AUTO_INCREMENT=24169513
/*!50100 PARTITION BY RANGE (`msg_timestamp`)
(PARTITION p2016_02 VALUES LESS THAN (1456779600) ENGINE = InnoDB,
PARTITION p2016_03 VALUES LESS THAN (1459458000) ENGINE = InnoDB,
PARTITION p2016_04 VALUES LESS THAN (1462050000) ENGINE = InnoDB,
PARTITION p2016_05 VALUES LESS THAN (1464728400) ENGINE = InnoDB,
PARTITION p2016_06 VALUES LESS THAN (1467320400) ENGINE = InnoDB,
PARTITION p2016_07 VALUES LESS THAN (1469998800) ENGINE = InnoDB,
PARTITION p2016_08 VALUES LESS THAN (1472677200) ENGINE = InnoDB,
PARTITION p2016_09 VALUES LESS THAN (1475269200) ENGINE = InnoDB,
PARTITION p2016_10 VALUES LESS THAN (1477947600) ENGINE = InnoDB,
PARTITION p2016_11 VALUES LESS THAN (1480539600) ENGINE = InnoDB,
PARTITION p2016_12 VALUES LESS THAN (1483218000) ENGINE = InnoDB,
PARTITION p2017_01 VALUES LESS THAN (1485896400) ENGINE = InnoDB,
PARTITION p2017_02 VALUES LESS THAN (1488315600) ENGINE = InnoDB,
PARTITION p2017_03 VALUES LESS THAN (1490994000) ENGINE = InnoDB,
PARTITION p2017_04 VALUES LESS THAN (1493586000) ENGINE = InnoDB,
PARTITION p2017_05 VALUES LESS THAN (1496264400) ENGINE = InnoDB,
PARTITION p2017_06 VALUES LESS THAN (1498856400) ENGINE = InnoDB,
PARTITION p2017_07 VALUES LESS THAN (1501534800) ENGINE = InnoDB,
PARTITION p2017_08 VALUES LESS THAN (1504213200) ENGINE = InnoDB,
PARTITION p2017_09 VALUES LESS THAN (1506805200) ENGINE = InnoDB,
PARTITION p2017_10 VALUES LESS THAN (1509483600) ENGINE = InnoDB,
PARTITION p2017_11 VALUES LESS THAN (1512075600) ENGINE = InnoDB,
PARTITION p2017_12 VALUES LESS THAN (1514754000) ENGINE = InnoDB,
PARTITION p2018_01 VALUES LESS THAN (1517432400) ENGINE = InnoDB,
PARTITION p2018_02 VALUES LESS THAN (1519851600) ENGINE = InnoDB,
PARTITION p2018_03 VALUES LESS THAN (1522530000) ENGINE = InnoDB,
PARTITION p2018_04 VALUES LESS THAN (1525122000) ENGINE = InnoDB,
PARTITION p2018_05 VALUES LESS THAN (1527800400) ENGINE = InnoDB,
PARTITION p2018_06 VALUES LESS THAN (1530392400) ENGINE = InnoDB,
PARTITION p2018_07 VALUES LESS THAN (1533070800) ENGINE = InnoDB,
PARTITION p2018_08 VALUES LESS THAN (1535749200) ENGINE = InnoDB,
PARTITION p2018_09 VALUES LESS THAN (1538341200) ENGINE = InnoDB,
PARTITION p2018_10 VALUES LESS THAN (1541019600) ENGINE = InnoDB,
PARTITION p2018_11 VALUES LESS THAN (1543611600) ENGINE = InnoDB,
PARTITION p2018_12 VALUES LESS THAN (1546290000) ENGINE = InnoDB,
PARTITION p2019_01 VALUES LESS THAN (1548968400) ENGINE = InnoDB,
PARTITION p2019_02 VALUES LESS THAN (1551387600) ENGINE = InnoDB,
PARTITION p2019_03 VALUES LESS THAN (1554066000) ENGINE = InnoDB,
PARTITION p2019_04 VALUES LESS THAN (1556658000) ENGINE = InnoDB,
PARTITION p2019_05 VALUES LESS THAN (1559336400) ENGINE = InnoDB,
PARTITION p2019_06 VALUES LESS THAN (1561928400) ENGINE = InnoDB,
PARTITION p2019_07 VALUES LESS THAN (1564606800) ENGINE = InnoDB,
PARTITION p2019_08 VALUES LESS THAN (1567285200) ENGINE = InnoDB,
PARTITION p2019_09 VALUES LESS THAN (1569877200) ENGINE = InnoDB,
PARTITION p2019_10 VALUES LESS THAN (1572555600) ENGINE = InnoDB,
PARTITION p2019_11 VALUES LESS THAN (1575147600) ENGINE = InnoDB,
PARTITION p2019_12 VALUES LESS THAN (1577826000) ENGINE = InnoDB,
PARTITION p2020_01 VALUES LESS THAN (1580504400) ENGINE = InnoDB,
PARTITION p2020_02 VALUES LESS THAN (1583010000) ENGINE = InnoDB,
PARTITION p2020_03 VALUES LESS THAN (1585688400) ENGINE = InnoDB,
PARTITION p2020_04 VALUES LESS THAN (1588280400) ENGINE = InnoDB,
PARTITION p2020_05 VALUES LESS THAN (1590958800) ENGINE = InnoDB,
PARTITION p2020_06 VALUES LESS THAN (1593550800) ENGINE = InnoDB,
PARTITION p2020_07 VALUES LESS THAN (1596229200) ENGINE = InnoDB,
PARTITION p2020_08 VALUES LESS THAN (1598907600) ENGINE = InnoDB,
PARTITION p2020_09 VALUES LESS THAN (1601499600) ENGINE = InnoDB,
PARTITION p2020_10 VALUES LESS THAN (1604178000) ENGINE = InnoDB,
PARTITION p2020_11 VALUES LESS THAN (1606770000) ENGINE = InnoDB,
PARTITION p2020_12 VALUES LESS THAN (1609448400) ENGINE = InnoDB,
PARTITION p2021_01 VALUES LESS THAN (1612126800) ENGINE = InnoDB,
PARTITION p2021_02 VALUES LESS THAN (1614546000) ENGINE = InnoDB,
PARTITION p2021_03 VALUES LESS THAN (1617224400) ENGINE = InnoDB,
PARTITION p2021_04 VALUES LESS THAN (1619816400) ENGINE = InnoDB,
PARTITION p2021_05 VALUES LESS THAN (1622494800) ENGINE = InnoDB,
PARTITION p2021_06 VALUES LESS THAN (1625086800) ENGINE = InnoDB,
PARTITION p2021_07 VALUES LESS THAN (1627765200) ENGINE = InnoDB,
PARTITION p2021_08 VALUES LESS THAN (1630443600) ENGINE = InnoDB,
PARTITION p2021_09 VALUES LESS THAN (1633035600) ENGINE = InnoDB,
PARTITION p2021_10 VALUES LESS THAN (1635714000) ENGINE = InnoDB,
PARTITION p2021_11 VALUES LESS THAN (1638306000) ENGINE = InnoDB,
PARTITION p2021_12 VALUES LESS THAN (1640984400) ENGINE = InnoDB,
PARTITION p2022_01 VALUES LESS THAN (1643662800) ENGINE = InnoDB,
PARTITION p2022_02 VALUES LESS THAN (1646082000) ENGINE = InnoDB,
PARTITION p2022_03 VALUES LESS THAN (1648760400) ENGINE = InnoDB,
PARTITION p2022_04 VALUES LESS THAN (1651352400) ENGINE = InnoDB,
PARTITION p2022_05 VALUES LESS THAN (1654030800) ENGINE = InnoDB,
PARTITION p2022_06 VALUES LESS THAN (1656622800) ENGINE = InnoDB,
PARTITION p2022_07 VALUES LESS THAN (1659301200) ENGINE = InnoDB,
PARTITION p2022_08 VALUES LESS THAN (1661979600) ENGINE = InnoDB,
PARTITION p2022_09 VALUES LESS THAN (1664571600) ENGINE = InnoDB,
PARTITION p2022_10 VALUES LESS THAN (1667250000) ENGINE = InnoDB,
PARTITION p2022_11 VALUES LESS THAN (1669842000) ENGINE = InnoDB,
PARTITION p2022_12 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */;
It's contains log data as follows:
id
provider
DLR_Status
source
Destination
msg
timestamp
msg_timestamp
1
KDD
done
website
01332456
free delivery
2019-12-01 12:00:13
1575201613
2
KDD
done
By phone
01322422
with cost 300
2019-12-01 12:00:37
1575201637
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
The issue is that when i select some counts from this table like
SELECT SQL_CALC_FOUND_ROWS DLR_status,count(*) as c
FROM sms_details
group by DLR_status;
It's take very long time to give the results and some query give 504 Gateway Time-out error like this query
SELECT SQL_CALC_FOUND_ROWS Destination,count(*) as c
FROM sms_details
WHERE msg_timestamp >= UNIX_TIMESTAMP("2019-10-01") and msg_timestamp < UNIX_TIMESTAMP("2019-12-01") group by Destination;
I am already use partitioning in my table
and I tried to indexing some column but that make big problem with daily increasing data.
So what is the best practices for the following:
Speed up execution time
Caring about an insert speed
Shrink schema -- Smaller --> less I/O --> faster.
timestamp vs msg_timestamp -- These seem to be the same, just in different formats. Of so, toss one of them.
Normalization speeds up the inserts some -- by shrinking the amount of data. Most of the VARCHARs could be replaced by a 2-byte SMALLINT UNSIGNED or a 3-byte MEDIUMINT UNSIGNED`.
Future partitions -- Do not have more than one such; the SELECTs will waste time opening them to find nothing.
Too many partitions -- At some limit (maybe 50), having lots of partitions slows things down.
Batching is the best speedup. See LOAD DATA or INSERT ... VALUES (...), (...), .... In the latter case, I recommend batches of 1000 rows. (Going beyond that is getting into diminishing returns and possibly some limits.) If the data is coming from multiple sources, explain; then we can talk further.
Partitioning is very useful for purging 'old' data because DROP PARTITION is a lot faster than DELETE. See http://mysql.rjweb.org/doc.php/partitionmaint
Toss created_at and updated_at; they are probably useless. (Again, smaller is faster.)
SQL_CALC_FOUND_ROWS is not needed when you don't have LIMIT; simply observe how many rows are returned. Rethink the user requirement for such. (Come back for more discussion, if desired.)
DLR_status counts will be a full index scan if you have INDEX(DLR_status). And consider making that column an ENUM so that it is only 1 byte. (If there are several values and/or a growing number of values, then "normalize".)
Query 2 needs INDEX(Destination, msg_timestmap).
Is it big? 24M rows / 5 years --> less than 1 row per second. 100 rows/sec is where I start to worry about "high-speed ingestion". That is, I don't see a problem with inserts. Selects, on the other hand, may be a problem. You showed us two; let's see more. I don't want to recommend one index at a time; I would rather design a set of indexes to optimally handle all the likely queries. Especially since it may involve redesigning the partitioning.
Summary tables are an excellent way to do fast analysis in a "Data warehouse". See http://mysql.rjweb.org/doc.php/summarytables

RANGE vs HASH partitioning for storage by Month in MySQL

For my Table, I need to partition based on created timestamp field by Month.
I am evaluating the following two approaches:
RANGE
ALTER TABLE my_table
PARTITION BY RANGE ( MONTH(created) ) (
PARTITION p1 VALUES LESS THAN (2),
PARTITION p2 VALUES LESS THAN (3),
PARTITION p3 VALUES LESS THAN (4),
PARTITION p4 VALUES LESS THAN (5),
PARTITION p5 VALUES LESS THAN (6),
PARTITION p6 VALUES LESS THAN (7),
PARTITION p7 VALUES LESS THAN (8),
PARTITION p8 VALUES LESS THAN (9),
PARTITION p9 VALUES LESS THAN (10),
PARTITION p10 VALUES LESS THAN (11),
PARTITION p11 VALUES LESS THAN (12),
PARTITION p12 VALUES LESS THAN (13)
);
HASH
ALTER TABLE my_table
PARTITION BY HASH((YEAR(created) * 100) + MONTH(created))
PARTITIONS 13;
Use case:
My use case is that I want to archive by month, for the month which has crosses 1 year. For example, if the current month is july-2020, then the parition corresponsing to july-2019 would be archived, also the secondary use case is the partition pruning to improve the performance as most of the queries include this timestamp column.
Why 13 partitions in the HASH one?
As stated above, I will be archiving the 13th month from current month.
For this use case, which approach would suit better? As far as I understand, when I'm defining it by RANGE, I have the directly control on which data goes into which partition, and in case of HASH, it would be defined by MySQL HASH function (mod) and that will make things difficult to identify the "over the year" partition and archive it specifically.
Or is there any totally different approach for this use case?
PARTITION BY HASH is useless. Period.
PARTITION BY RANGE can be useful if you want to purge "old" data. Details: http://mysql.rjweb.org/doc.php/partitionmaint
What will you do next January?
Show me your SELECTs and SHOW CREATE TABLE. I'll help you optimize the INDEXes for a non-partitioned version. It will run as fast or faster than you think your schema.
More
BY HASH is useless when you have a "range". The Optimizer will always pick all partitions, thereby slowing down the query. (This flaw applies to most partitioning methods.)
If you always use WHERE month=constant, you may as well have the column month early in indexes. MONTH(date_col) = constant is a different matter. (I have not thought through all the implications. Let's see your queries.)
As a general rule, you can build an index on a non-partitioned table that will provide the equivalent functionality as partition pruning. (The link lists only 4 exceptions to the rule. I've spent a decade looking for more use cases.) Correlary: When switching to/from partitioning, all the indexes, including the PRIMARY KEY, should be redesigned.
One of my use cases is to use "transportable tablespaces" to archive one whole partition. You might be able to use that with BY HASH; it's rather clear how to do it with BY RANGE.
The main focus of my blog is to explain DROPping (or 'transporting') the oldest of a 13-month partitions and REORGANIZE to get a new "month" (or other time range).

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 move or archive unused data

So I have decent size table with transactions. I can not redesign it or add more indexes. Data as is. Half of business logic do full scan anyway.
I get an idea to move some old/unused data to 'archive table' to speed up stuff a little and be able once in a while scan all data anyway. Or other direction around: create 'fast table' where I will have only fresh (last month or so) data, and normal table which will have all data.
Is anyone aware of this kind of technic or anything? Where to read? better approaches? How to implement in code or something.
For now we have around 50 mil rows of data with crazy partitions which made more harm then use.
PARTITION BY LIST (user_id%20)
SUBPARTITION BY KEY (user_role)
SUBPARTITIONS 4
(PARTITION p0 VALUES IN (0) ENGINE = InnoDB,
PARTITION p1 VALUES IN (1) ENGINE = InnoDB,
PARTITION p2 VALUES IN (2) ENGINE = InnoDB,
PARTITION p3 VALUES IN (3) ENGINE = InnoDB,
PARTITION p4 VALUES IN (4) ENGINE = InnoDB,
PARTITION p5 VALUES IN (5) ENGINE = InnoDB,
PARTITION p6 VALUES IN (6) ENGINE = InnoDB,
PARTITION p7 VALUES IN (7) ENGINE = InnoDB,
PARTITION p8 VALUES IN (8) ENGINE = InnoDB,
PARTITION p9 VALUES IN (9) ENGINE = InnoDB,
PARTITION p10 VALUES IN (10) ENGINE = InnoDB,
PARTITION p11 VALUES IN (11) ENGINE = InnoDB,
PARTITION p12 VALUES IN (12) ENGINE = InnoDB,
PARTITION p13 VALUES IN (13) ENGINE = InnoDB,
PARTITION p14 VALUES IN (14) ENGINE = InnoDB,
PARTITION p15 VALUES IN (15) ENGINE = InnoDB,
PARTITION p16 VALUES IN (16) ENGINE = InnoDB,
PARTITION p17 VALUES IN (17) ENGINE = InnoDB,
PARTITION p18 VALUES IN (18) ENGINE = InnoDB,
PARTITION p19 VALUES IN (19) ENGINE = InnoDB)
Where 3 different user_role and around 20 rows per uniq user_id. Do not ask me what the hell, it just is what it is....
Thank you.
PS: I absolutely understand it is better invest time to fully analyze and redesign table itself, however sometimes it's impossible 'cuz of politics and simple shitty people who above you in food chain.
You may want to look into Table Partitioning
, specifically Range Partitioning:
If you partition you table by the date column/timestamp, Mysql will then only scan an appropriate partition, during the query:
You frequently run queries that depend directly on the column used for partitioning the table. For example, when executing a query such as EXPLAIN PARTITIONS SELECT COUNT(*) FROM employees WHERE separated BETWEEN '2000-01-01' AND '2000-12-31' GROUP BY store_id;, MySQL can quickly determine that only partition p2 needs to be scanned because the remaining partitions cannot contain any records satisfying the WHERE clause.

What is the mistake in this MySQL partition query?

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.