particiones en mysql y oracle
TRANSCRIPT
Particiones en MySQL y OracleParticiones en MySQLParticionar tablas en MySQL nos permite rotar la información de nuestras tablas en diferentes particiones, consiguiendo así realizar consultas más rápidas y recuperar espacio en disco al borrar los registros. El uso más común de particionado es según fecha (date).Para ver si nuestra base de datos soporta particionado simplemente ejecutamos:
SHOW VARIABLES LIKE '%partition%';
A continuación veremos un ejemplo de cómo particionar una tabla por mes y posteriormente borrar o modificar su información.
Crear particiones
1.- Creamos la tabla reports:CREATE TABLE reports ( id int(10) NOT NULL AUTO_INCREMENT, date datetime NOT NULL, report TEXT, PRIMARY KEY (id,date)) ENGINE=InnoDB DEFAULT CHARSET=utf8
Como se puede ver hemos añadido como índice de tabla el campo date, esto es necesario si luego queremos particionar por fecha.
2.- Ahora que tenemos la tabla creada vamos a particionar por mes:
ALTER TABLE reports PARTITION BY RANGE(TO_DAYS(date))( PARTITION p201111 VALUES LESS THAN (TO_DAYS("2011-12-01")), PARTITION p201112 VALUES LESS THAN (TO_DAYS("2012-01-01")), PARTITION p201201 VALUES LESS THAN (TO_DAYS("2012-02-01")), PARTITION p201202 VALUES LESS THAN (TO_DAYS("2012-03-01")), PARTITION p201203 VALUES LESS THAN (TO_DAYS("2012-04-01")), PARTITION p201204 VALUES LESS THAN (TO_DAYS("2012-05-01")), PARTITION p201205 VALUES LESS THAN (TO_DAYS("2012-06-01")), PARTITION pDefault VALUES LESS THAN MAXVALUE);
La última partición (pDefault) tendrá todos los registros que no entren en las particiones anteriores. De esta manera nos aseguramos que la información nunca dejará de insertarse en la tabla.
Borrar particiones
Lo bueno de trabajar con particiones es que podemos borrar rápidamente registros sin tener que recorrer toda la tabla e inmediatamente recuperar el espacio en disco utilizado por la tabla.Por ejemplo si queremos borrar la partición más antigua simplemente ejecutamos:
ALTER TABLE reports DROP PARTITION p201111;
Añadir particiones
En el ejemplo anterior las 2 últimas particiones creadas han sido:
PARTITION p201205 VALUES LESS THAN (TO_DAYS("2012-06-01")),PARTITION pDefault VALUES LESS THAN MAXVALUE
El problema es que todos los INSERTs que se hagan después de mayo de 2012 se insertarán en pDefault. La solución sería añadir particiones nuevas para cubrir los próximos meses:ALTER TABLE reports REORGANIZE PARTITION pDefault INTO (PARTITION p201206 VALUES LESS THAN (TO_DAYS("2012-07-01")),PARTITION pDefault VALUES LESS THAN MAXVALUE);
En el caso que no tuvieramos una partición del tipo pDefault simplemente ejecutamos:ALTER TABLE reports ADD PARTITION (PARTITION p201206 VALUES LESS THAN (TO_DAYS("2012-07-01")));
Consultar particiones
Para consultar información de particiones creadas en una tabla así como también los registros que contiene cada una ejecutamos:SELECT PARTITION_NAME,TABLE_ROWS FROM information_schema.PARTITIONS WHERE TABLE_NAME='reports'; --------------------------------------------------------------
Por rango: para construir nuestras particiones especificamos rangos de valores.
Por ejemplo, podríamos segmentar los datos en 12 particiones: una para los
contratos de 1950 a 1960, otra para los años 60, los 70, 80, 90, la década del
2000 y la década actual
view plaincopy to clipboardprint?
1. ALTER TABLE contratos 2. PARTITION BY RANGE(YEAR(fechaInicio)) ( 3. PARTITION partDecada50 VALUES LESS THAN (1960), 4. PARTITION partDecada60 VALUES LESS THAN (1970), 5. PARTITION partDecada70 VALUES LESS THAN (1980), 6. PARTITION partDecada80 VALUES LESS THAN (1990), 7. PARTITION partDecada90 VALUES LESS THAN (2000), 8. PARTITION partDecada00 VALUES LESS THAN (2010), 9. PARTITION partDecada10 VALUES LESS THAN MAXVALUE 10. );
Por listas: para construir nuestras particiones especificamos listas de valores
concretos.
view plaincopy to clipboardprint?
1. ALTER TABLE contratos 2. PARTITION BY LIST(YEAR(fechaInicio)) ( 3. PARTITION partDecada50 VALUES IN (1950, 1951, 1952, 1953, 1954, 19
55, 1956, 1957, 1958, 1959), 4. PARTITION partDecada60 VALUES IN (1960, 1961, 1962, 1963, 1964, 19
65, 1966, 1967, 1968, 1969), 5. PARTITION partDecada70 VALUES IN (1970, 1971, 1972, 1973, 1974, 19
75, 1976, 1977, 1978, 1979),
6. PARTITION partDecada80 VALUES IN (1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989),
7. PARTITION partDecada90 VALUES IN (1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999),
8. PARTITION partDecada00 VALUES IN (2000, 2001, 2002, 2003, 2004, 2005, 2006,
9. 2007, 2008, 2009), 10. PARTITION partDecada10 VALUES IN (2010, 2011, 2012, 2013, 2014, 20
15, 2016, 11. 2017, 2018, 2019) 12. );
Por hash: MySQL se encarga de distribuir las tuplas automáticamente usando una
operación de módulo. Sólo hay que pasarle una columna o expresión que resulte
en un entero (el hash) y el número de particiones que queramos crear.
view plaincopy to clipboardprint?
1. ALTER TABLE contratos 2. PARTITION BY HASH(YEAR(fechaInicio)) 3. PARTITIONS 7;
Por clave: similar a la partición por hash, pero en este caso no necesitamos
pasarle un entero; MySQL utilizará su propia función de hash para generarlo. Si no
se indica ninguna columna a partir de la que generar el hash, se utiliza la clave
primaria por defecto.
view plaincopy to clipboardprint?
1. ALTER TABLE contratos 2. PARTITION BY KEY() 3. PARTITIONS 7;
Compuesta: podemos combinar los distintos métodos de particionado y crear
particiones de particiones
Por último, un pequeño ejemplo de cómo afectaría el particionado a una consulta sencilla
como obtener el número total de tuplas que cumplen una condición. Estas son las
estadísticas de la consulta sin particionado (ni índices)
view plaincopy to clipboardprint?
1. EXPLAIN SELECT COUNT(*) 2. FROM contratos 3. WHERE fechaInicio BETWEEN '1950-01-01' AND '1955-12-31'
select_type
table typekey
rows Extra
SIMPLEcontratos
ALL
239796
Using where
Y este el resultado de añadir las particiones (nótese la palabra clave PARTITIONS para que
nos muestre también la información relativa a las particiones)
view plaincopy to clipboardprint?
1. EXPLAIN PARTITIONS SELECT COUNT(*)
2. FROM contratos 3. WHERE fechaInicio BETWEEN '1950-01-01' AND '1955-12-31'
select_type
table partitions typekeyrows
Extra
SIMPLEcontratos
partDecada50
ALL
8640Using where
Como véis, el número de tuplas que MySQL tiene que comprobar se ve disminunido en 2
órdenes de magnitud.
Sintaxis para la creación de las tablas
La estructura de la tabla “NonFTP_Access_log” sin particionar corresponde a la definida en la
siguiente consulta SQL CREATE TABLE
CREATE TABLE `NonFTP_Access_log` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `clientip` VARCHAR(15) NOT NULL, `user` CHAR(7) NOT NULL, `datetime` datetime NOT NULL, `method` VARCHAR(10) NOT NULL, `protocol` VARCHAR(10) NOT NULL, `domain` VARCHAR(255) NOT NULL, `uri` VARCHAR(100) NOT NULL, `return_code` SMALLINT(5) UNSIGNED NOT NULL, `size` INT(10) UNSIGNED NOT NULL, PRIMARY KEY (`id`), INDEX `domain` (`domain`), INDEX `datetime` (`datetime`)) ENGINE=MyISAM DEFAULT CHARSET=utf8
Y con particiones, una para cada mes del 2012 a la siguiente
CREATE TABLE `NonFTP_Access_log` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `clientip` VARCHAR(15) NOT NULL, `user` CHAR(7) NOT NULL, `datetime` datetime NOT NULL, `method` VARCHAR(10) NOT NULL, `protocol` VARCHAR(10) NOT NULL, `domain` VARCHAR(255) NOT NULL, `uri` VARCHAR(100) NOT NULL, `return_code` SMALLINT(5) UNSIGNED NOT NULL, `size` INT(10) UNSIGNED NOT NULL, PRIMARY KEY (`id`, `datetime`),
INDEX `domain` (`domain`), INDEX `datetime` (`datetime`)) ENGINE=MyISAM DEFAULT CHARSET=utf8partition BY range COLUMNS (datetime)(partition p1 VALUES less than ('2012-02-01 00:00:00') engine = myisam,partition p2 VALUES less than ('2012-03-01 00:00:00') engine = myisam,partition p3 VALUES less than ('2012-04-01 00:00:00') engine = myisam,partition p4 VALUES less than ('2012-05-01 00:00:00') engine = myisam,partition p5 VALUES less than ('2012-06-01 00:00:00') engine = myisam,partition p6 VALUES less than ('2012-07-01 00:00:00') engine = myisam,partition p7 VALUES less than ('2012-08-01 00:00:00') engine = myisam,partition p8 VALUES less than ('2012-09-01 00:00:00') engine = myisam,partition p9 VALUES less than ('2012-10-01 00:00:00') engine = myisam,partition p10 VALUES less than ('2012-11-01 00:00:00') engine = myisam,partition p11 VALUES less than ('2012-12-01 00:00:00') engine = myisam,partition p12 VALUES less than ('2013-01-01 00:00:00') engine = myisam);