web-dev-qa-db-fra.com

comment partitionner une table par colonne datetime?

Je veux partitionner une table mysql par colonne datetime. Un jour, une partition. Les scripts de création de table ressemblent à ceci:

CREATE TABLE raw_log_2011_4 (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  logid char(16) NOT NULL,
  tid char(16) NOT NULL,
  reporterip char(46) DEFAULT NULL,
  ftime datetime DEFAULT NULL,
  KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
PARTITION BY hash (day(ftime)) partitions 31;

Mais quand je sélectionne les données d’un jour. Il n’a pas pu localiser la partition.

explain partitions select * from raw_log_2011_4 where day(ftime) = 30;

lorsque j'utilise une autre déclaration, la partition peut être localisée, mais je ne peux pas sélectionner les données d'un jour.

explain partitions select * from raw_log_2011_4 where ftime = '2011-03-30';

Y a-t-il quelqu'un qui me dise comment je pourrais sélectionner des données d'un jour et utiliser une partition? Merci!

13
tinychen

Les partitions par HASH sont une très mauvaise idée avec les colonnes datetime, car elles ne peuvent pas utiliser partition élagage . De la documentation MySQL:

L'élagage ne peut être utilisé que sur des colonnes entières de tables partitionnées par HASH ou KEY. Par exemple, cette requête sur la table t4 ne peut pas utiliser l'élagage car dob est une colonne DATE:

SELECT * FROM t4 WHERE dob >= '2001-04-14' AND dob <= '2005-10-15';

Toutefois, si la table stocke les valeurs d'année dans une colonne INT, une requête ayant WHERE year_col> = 2001 AND year_col <= 2005 peut être élaguée.

Ainsi, vous pouvez stocker la valeur de TO_DAYS (DATE ()) dans une colonne INTEGER supplémentaire pour utiliser l'élagage.

Une autre option consiste à utiliser le partitionnement RANGE:

CREATE TABLE raw_log_2011_4 (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  logid char(16) NOT NULL,
  tid char(16) NOT NULL,
  reporterip char(46) DEFAULT NULL,
  ftime datetime DEFAULT NULL,
  KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
  PARTITION BY RANGE( TO_DAYS(ftime) ) (
    PARTITION p20110401 VALUES LESS THAN (TO_DAYS('2011-04-02')),
    PARTITION p20110402 VALUES LESS THAN (TO_DAYS('2011-04-03')),
    PARTITION p20110403 VALUES LESS THAN (TO_DAYS('2011-04-04')),
    PARTITION p20110404 VALUES LESS THAN (TO_DAYS('2011-04-05')),
    ...
    PARTITION p20110426 VALUES LESS THAN (TO_DAYS('2011-04-27')),
    PARTITION p20110427 VALUES LESS THAN (TO_DAYS('2011-04-28')),
    PARTITION p20110428 VALUES LESS THAN (TO_DAYS('2011-04-29')),
    PARTITION p20110429 VALUES LESS THAN (TO_DAYS('2011-04-30')),
    PARTITION future VALUES LESS THAN MAXVALUE
  );

Maintenant, la requête suivante utilisera uniquement la partition p20110403:

SELECT * FROM raw_log_2011_4 WHERE ftime = '2011-04-03';
18
Steyx

Salut Vous faites la mauvaise partition dans la définition de la table, la définition de la table aimerait ceci:

CREATE TABLE raw_log_2011_4 (
  id bigint(20) NOT NULL AUTO_INCREMENT,
  logid char(16) NOT NULL,
  tid char(16) NOT NULL,
  reporterip char(46) DEFAULT NULL,
  ftime datetime DEFAULT NULL,
  KEY id (id)
) ENGINE=InnoDB AUTO_INCREMENT=286802795 DEFAULT CHARSET=utf8
PARTITION BY hash (TO_DAYS(ftime)) partitions 31;

Et votre commande select serait:

explain partitions 
    select * from raw_log_2011_4 where TO_DAYS(ftime) = '2011-03-30';

La commande ci-dessus sélectionnerait toute la date requise, comme si vous utilisiez la commande TO_DAYS comme

mysql> SELECT TO_DAYS(950501);
        -> 728779
mysql> SELECT TO_DAYS('2007-10-07');
        -> 733321

Pourquoi utiliser TO_DAYS AS L'optimiseur MySQL reconnaîtra deux fonctions basées sur la date à des fins d'élagage de partition: 1.TO_DAYS () 2.YEAR ()

et cela résoudrait votre problème ..

9
Vineet1982

Je viens de lire un article de blog de MySQL sur ce sujet, à l’adresse http://dev.mysql.com/tech-resources/articles/mysql_55_partitioning.html .

Les versions antérieures à 5.1 nécessitaient une gymnastique spéciale pour effectuer le partitionnement en fonction des dates. Le lien ci-dessus en discute et montre des exemples.

Les versions 5.5 et supérieures vous autorisaient à effectuer un partitionnement direct à l'aide de valeurs non numériques telles que des dates et des chaînes.

1
John Rocha

N'utilisez pas CHAR, utilisez VARCHAR. Cela permettra d'économiser beaucoup d'espace et donc de diminuer les E/S, donc d'accélérer les requêtes.

reporterip: (46) est inutilement grand pour une adresse IP, même IPv6. Voir Mon blog pour plus d'informations, y compris comment le réduire à 16 octets.

PARTITION BY RANGE(TO_DAYS(...)) comme @Steyx l'a suggéré, mais ne comptez pas plus de 50 partitions. Plus vous avez de partitions, plus les requêtes sont lentes, malgré la "taille". HASH le partitionnement est essentiellement inutile.

Plus de discussion sur le partitionnement, en particulier le type que vous regardez . Cela inclut du code pour un ensemble coulissant de partitions au fil du temps.

0
Rick James