List partition for remaining items - mysql

when partitioning tables in MySQL using a list, how can I generate a partition for remaining items?
E.G:
CREATE TABLE tbl
(
ID integer
)
PARTITION BY LIST (ID)
(
PARTITION P1 values in (1),
PARTITION P2 values in (2),
PARTITION P3 values in (3),
PARTITION Pother values in (<all remaining values of ID>)
);
In Oracle, I use values in (default), but that does work in MySQL.

Unlike range partitioning, there is no "catch-all" in list partitioning. To quote the documentation:
Unlike the case with RANGE partitioning, there is no “catch-all” such
as MAXVALUE; all expected values for the partitioning expression
should be covered in PARTITION ... VALUES IN (...) clauses. An INSERT
statement containing an unmatched partitioning column value fails with
an error...
Unfortunately, I believe, you're not able to combine a list and a range partition either. I'm not entirely certain why you would want to use a list partition in this particular instance; wouldn't a range partition work just a well?
CREATE TABLE tbl
(
ID integer
)
PARTITION BY RANGE (ID)
(
PARTITION P1 values less than (2),
PARTITION P2 values less than (3),
PARTITION P3 values less than (4),
PARTITION Pother values less than maxvalue
);
I'm assuming that this is just an example. Partitioning each key in a primary key is a little pointless.

Related

SQL Partitioning of a very large table

I'm trying to partition my very large MySQL table called companyScores (60million rows and 50 columns).
Basically, the table features companies (with the column varchar "company_idx" with unique IDs going from 0 to 10,000 companies) and their respective timestamp (with the column "timestamp") and scores "Scores" (with the column "Scores").
I'd like to include around 500 companies into each partition.
Please let me know if the following would do the job?
ALTER TABLE `companyScores`
PARTITION BY RANGE( company_idx ) (
PARTITION p0 VALUES LESS THAN (500),
PARTITION p1 VALUES LESS THAN (1000),
PARTITION p2 VALUES LESS THAN (1500),
PARTITION p3 VALUES LESS THAN (2000),
and so on...
);
Would the above work?
Also, can we easily insert new values into this database once it has been partitioned?
Would the above work?
No. For several reasons.
If company_idx is a varchar, you need to use RANGE COLUMNS. The RANGE partitioning only works on integers. If you try to use RANGE partitioning on a varchar, you get this error:
ERROR 1659 (HY000): Field 'company_idx' is of a not allowed type for this type of partitioning
Assuming you correct that, you have another problem:
Your partition clauses use integer values, not quoted string values. Those are different types, and the partitioning engine won't use them for defining partitions. If you try, you'll this this error:
ERROR 1654 (HY000): Partition column values of incorrect type
Assuming you correct that by quoting the numbers, you have another problem:
You list the partition for 500 before the string 1000, but the string '500' should come after the string '1000' lexically. RANGE or RANGE COLUMNS partitions must be declared in increasing order. If you try to do it in the order you have, you'll get this error:
ERROR 1493 (HY000): VALUES LESS THAN value must be strictly increasing for each partition
Assuming you correct the order, it works, but it might not do what you want:
CREATE TABLE `companyScores` (
`company_idx` varchar(10) NOT NULL,
PRIMARY KEY (`company_idx`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
/*!50500 PARTITION BY RANGE COLUMNS(company_idx)
(PARTITION p1 VALUES LESS THAN ('1000') ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN ('1500') ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN ('2000') ENGINE = InnoDB,
PARTITION p0 VALUES LESS THAN ('500') ENGINE = InnoDB) */
Now another question you asked:
Also, can we easily insert new values into this database once it has been partitioned?
If you insert a new value that isn't covered by the partitions you defined, you'll get this error:
mysql> insert into companyScores set company_idx = '700';
ERROR 1526 (HY000): Table has no partition for value from column_list
Why is that? You have a partition for company_idx less than 1000 right?
No. You have a partition for company_idx less than the string '1000'. You tried to insert the string '700', which is lexically greater than '500', as well as all the other partitions. Therefore it's beyond any of the partitions defined.
You could solve all of the above problems if you change your customer_idx to an integer column.

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);

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)
);

Partition using Month of TIMESTAMP

I have a table employees which i need to partition based on the month of timestamp. I have tried some types buts not working.
CREATE TABLE employees (
id INT NOT NULL,
fname VARCHAR(30),
lname VARCHAR(30),
hired DATE NOT NULL DEFAULT '1970-01-01',
separated TIMESTAMP NOT NULL DEFAULT '9999-12-31',
job_code INT,
store_id INT
)
PARTITION BY RANGE ( date_format(separated,'%m') ) (
PARTITION p0 VALUES LESS THAN (01),
PARTITION p1 VALUES LESS THAN (02),
PARTITION p2 VALUES LESS THAN (03),
----
PARTITION p4 VALUES LESS THAN (04)
);
when am creating this table it is showing that this partition function is not allowed
if am using MONTH(seperated) it works for DATE type but it returns invalid default value for seperated
How we do it in our project (may be not the right way, but works for us) - (MySQL 5.1.60)
PARTITION p201 VALUES LESS THAN (TO_DAYS('2012-01-01')),
PARTITION p202 VALUES LESS THAN (TO_DAYS('2012-02-01')),
PARTITION p203 VALUES LESS THAN (TO_DAYS('2012-03-01')),
PARTITION p204 VALUES LESS THAN (TO_DAYS('2012-04-01')),
PARTITION p205 VALUES LESS THAN (TO_DAYS('2012-05-01')),
PARTITION p206 VALUES LESS THAN (TO_DAYS('2012-06-01')),
PARTITION p207 VALUES LESS THAN (TO_DAYS('2012-07-01')),
PARTITION p208 VALUES LESS THAN (TO_DAYS('2012-08-01')),
PARTITION p209 VALUES LESS THAN (TO_DAYS('2012-09-01')),
PARTITION p210 VALUES LESS THAN (TO_DAYS('2012-10-01')),
PARTITION p211 VALUES LESS THAN (TO_DAYS('2012-11-01')),
PARTITION p212 VALUES LESS THAN (TO_DAYS('2012-12-01'))
That is partitioning for Complete year of 2012