Mostrando entradas con la etiqueta mysql. Mostrar todas las entradas
Mostrando entradas con la etiqueta mysql. Mostrar todas las entradas

jueves, 4 de agosto de 2011

Hacer respaldos de Bases de Datos MySQL con MySQLDump


El comando mysqldump proporciona una manera conveniente para respaldar datos y estructuras de tablas. Hay que notar que mientras el comando mysqldump no es el método más eficiente para crear respaldos ,éste ofrece un medio conveniente para copiar datos y estructuras de tablas que puede ser usado para “poblar” otro servidor SQL, no importando si se trata, o no de un servidor MySQL.
El comando mysqldump puede ser usado para crear respaldos de todas las bases de datos, algunas bases de datos, sólo una de ellas, o incluso ciertas tablas de una base de datos dada. En esta sección se ilustra la sintaxis involucrada con varios posibles escenarios, seguida con unos pocos ejemplos.
Desde una ventana de comandos nos posicionamos en la carpeta “bin” de nuestro directorio mysql y podemos usar las siguientes instrucciones:
Usando el comando mysqldump para respaldar sólo una base de datos:
bin> mysqldump [opciones] nombre_base_datos
Usando el comando mysqldump para respaldar varias tablas de una base de datos:
bin> mysqldump [opciones] nombre_base_datos tabla1 tabla2. . . tablaN
Usando mysqldump para respaldar varias bases de datos:
bin> mysqldump [opciones] --databases [opciones] nombre_bd1 nombre_bd2...
Usando mysqldump para respaldar todas las bases de datos:
bin> mysqldump [opciones] --all-databases [opciones]
Las opciones pueden ser vistas ejecutando el siguiente comando:
bin> mysqldump --help
- Ejemplos -
Respaldar ambos, la estructura y los datos encontrados dentro de la base de datos widgets puede ser realizado como sigue:
bin> mysqldump -u root -p --opt widgets
Alternativamente, quizás se requiera respaldar únicamente los datos, esto es logrado al incluir la opción –no-create-info, lo que significa que no se creen los datos relativos a la creación de las tablas.
bin>mysqldump -u root -p --no-create-info widgets
Otra variación es respaldar únicamente la estructura de las tablas, esto es logrado al incluir la opción –no-data, que significa la no creación de los datos de las tablas.
bin>mysqldump -u root -p --no-data widgets
Si se está planeando usar mysqldump con el fin de respaldar datos para que puedan ser movidos a otro servidor MySQL, es recomendado que se use la opción “–opt”. Esto nos dará un respaldo optimizado de los datos que tendrá como resultado un tiempo más rápido de lectura cuando se quieran cargar los datos en otro servidor MySQL.
Mientras mysqldump proporciona un método conveniente para respaldar datos, hay un segundo método, el cuales más rápido, y más eficiente. Esto se describe en la siguiente sección.
Visto de una forma msencilla como ejemplos tenemos los siguiente:
Para copiar estructura y datos:
c:\mysql\bin>mysqldump -u root -p –opt nombreDeMiDBOrigenaRespaldar > nombreRespaldo.sql
Para copiar solo datos:
c:\mysql\bin>mysqldump -u root -p –no-create-info nombreDeMiDBOrigenaRespaldar > nombreRespaldo.sql
Para copiar solo estructura:
c:\mysql\bin>mysqldump -u root -p –no-data nombreDeMiDBOrigenaRespaldar > nombre_respaldo.sql
Y para recuperar una copia de seguridad:
C:\mysql\bin>mysql -u root -p contraseña dbDondeSeVaArespaldar < respaldoACargar.sql

martes, 2 de agosto de 2011

Particionando en MySQL 5.1

Particionado de tablas en MySQL

¿Qué es el particionado de tablas?

El particionado de tablas en MySQL nos permite distribuir porciones de tablas en un sistema de ficheros. Esta distribución se realiza de acuerdo a reglas definidas por el usuario para ajustarse a sus necesidades. Estas reglas reciben el nombre de funciones de particionado y existen varios tipos de funciones distintas: particionado por rangos o listas de valores, funciones hash internas o lineales y por clave.

¿Qué tipos de particionados tenemos disponibles?

Existen dos tipos de particionados: particionado horizontal, en el que las distintas filas de la tabla se asignan una partición en concreto; y el particionado vertical, en el que las distintas columnas de la tabla se asignan a una partición en concreto. Actualmente (versión 5.5 de MySQL), sólo está soportado el particionamiento horizontal.

¿Qué ventajas tiene el particionado de tablas?

La ventaja principal del particionado de tablas es la optimización a la hora de acceder a los datos que almacena MySQL, ya que podemos unificar datos comunes en las mismas particiones. En otras palabras, a la hora de realizar una consulta a una tabla particionada, en lugar de realizar búsquedas por toda la tabla, reduciremos la búsqueda a aquellas particiones en las que sepamos que hay datos que nos interesen.
Como ejemplo, si tenemos una base de datos en la que almacenamos las ventas que realizan distintas tiendas de una cadena, y particionamos la tabla ventas por la identificación de cada tienda, guardaremos en cada partición los datos de ventas relativos a cada tienda. Así si queremos buscar los datos de la tienda de Albacete, sólo buscaremos en la partición asignada a ésta ciudad, ya que sería absurdo buscar datos de ventas de la tienda de Albacete en cualquier otra tienda.
Otra ventaja del particionado es que nos aporta mucha flexibilidad si pensamos en escalar nuestra base de datos, ya que por ejemplo, podemos guardar cada partición en distintos discos físicos.
Hay que tener en cuenta que estas ventajas tienen sus inconvenientes, ya que la complejidad de administración de nuestra base de datos se incrementará, al igual que el diseño de las tablas, etc… Lo ideal, como siempre es alcanzar un equilibrio entre los beneficios que conseguiremos y el coste de mantener el sistema.

¿Qué limitaciones tiene el particionado de tablas?

  • Debemos utilizar el mismo motor de almacenamiento para todas las particiones de la misma tabla (es decir, que no podremos utilizar MyISAM para una partición e InnoDB para otra).
  • En MySQL 5.5, no podemos utilizar particionado de tablas con todos los motores de almacenamiento disponibles. En particular, si utilizamos los motores de almacenamiento MERGE, CSV o FEDERATED no podremos aplicar esta técnica.
  • El particionado por clave es posible sólo si utilizamos el motor de almacenamiento NDBCLUSTER, pero no otro tipo de particionado definidos por el usuario.
  • No podremos utilizar funciones o procedimientos almacenados o plugins, ni declarar variables ni variables de usuario.
  • Podemos utilizar operadores aritméticos o lógicos siempre y cuando devuelvan un resultado de tipo entero oNULL (excepto en el caso de particionado por clave).
  • No podremos utilizar operadores a nivel de bits.
  • El tamaño máximo de particiones (incluyendo subparticiones) para una tabla es de 1024.
  • Las claves fornáneas no están soportadas.
  • Los índices FULLTEXT no están soportados en tablas particionadas.
  • Los tipos de datos POINT o GEOMETRY no se pueden utilizar en tablas particionadas.
  • Ni las tablas temporales ni las tablas de logs se pueden particionar.
  • El tipo de datos de una clave que se use para el particionado debe ser un entero o una expresión que devuelva un entero como resultado o bien NULL.
  • Una clave de particionado no puede ser una subconsulta.
  • La caché de claves no está soportada.
  • La opción DELAYED no está soportada.
  • mysqlcheck y myisamchk no están soportados a la hora de aplicarlo a tablas particionadas.
Es importante tener en cuenta estas limitaciones a la hora de plantearnos el particionado, ya que podríamos acabar en un callejón sin salida (por ejemplo, si decidimos particionar sin tener en cuenta que el número de particiones de una tabla puede crecer por encima del máximo permitido).

¿Qué necesitamos para utilizar el particionado de tablas con MySQL?

El único requisito necesario para utilizar el particionado es que los ejecutables de MySQL estén compilados con soporte para particionado. Los ejecutables de la versión Community de MySQL que distribuye Sun Microsystems incluyen el soporte para particionado.
Para comprobarlo, debemos utilizar el comando de MySQL “SHOW VARIABLES”:
Sentencia MySQL
En versiones anteriores a MySQL 5.1.6, la variable have_partitioning recibía otro nombre:have_partition_engine.
También podemos utilizar el comando “SHOW PLUGINS” (debemos observar la línea partition…) :
Sentencia MySQL

¿Cómo se crean particiones para una tabla?

Para crear particiones para una tabla, debemos utilizar algunos modificadores de la sentencia “CREATE TABLE” de MySQL:
CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
ENGINE=INNODB
PARTITION BY HASH( MONTH(tr_date) )
PARTITIONS 6;
La línea:
PARTITION BY HASH( MONTH(tr_date) )
Indica el tipo de particionado que vamos a aplicar, en este caso por hash interno. La distribución de los datos debería ser lo más homogénea posible si el objetivo es la distribución equitativa de los datos a través de las particiones. Ésto dependerá directamente de la calidad de la función hash.
La línea:
PARTITIONS 6;
establece el número de particiones que vamos a utilizar para la tabla.
Notas:
El particionado de una tabla afectará tanto a los índices de la tabla como a los datos. No podemos particionar sólo los índices o sólo los datos.
Lo que sí que podemos hacer es asignar para cada partición un directorio para los datos y otro directorio para los índices.
En caso de que utilicemos el motor de almacenamiento InnoDB, la asignación de distintos directorios para índices y para datos no tendrá efecto.
En Windows se ignoran las opciones de separación de datos e índices en distintos directorios.

Particionado por rango

Este tipo de particionado asigna a cada partición un rango de valores. Podemos utilizar este particionado cuando:
  • Necesitamos borrar datos que ya no nos sirven. Por ejemplo, si hemos particionado por años y queremos deshacernos de los datos de uno de los años, lo único que tendremos que hacer es eliminar la partición correspondiente utilizando la sentencia “ALTER TABLE” con las opciones adecuadas relativas al particionado.
  • Cuando queremos utilizar una columna que contenga valores de fechas o tiempo.
  • Cuando ejecutamos de forma frecuente consultas que dependen directamente en la columna que hemos utilizado para realizar el particionado.
Un subtipo de particionado parecido al de rango es el de lista, en el que se particiona según una lista de valores discretos proporcionados a la hora de crear la tabla.

Particionado por hash

Este tipo de particionado se utiliza cuando queremos una distribución homogénea de los datos en todas las particiones.
Como hemos mencionado anteriormente, debemos asignar una función de hash interna que el motor de MySQL ejecutará cada vez que se realiza una inserción o una actualización y eventualmente los borrados.
Existe un tipo especial de particionado por hash llamado hash lineal. Sin entrar en mucho detalle, elhash lineal proporciona más velocidad a la hora de añadir, borrar, fusionar y separar particiones. Este tipo de particionado es especialmente beneficioso cuando manejamos tablas con muchos datos (del orden de terabytes). La desventaja de este tipo de particionado es que la distribución de datos no es tan homogénea como con el método por hash estándar.

Particionado por clave

El particionado por clave es similar al particionado por hash, con la excepción de que es el usuario quién define la función hash.

Subparticionado

También llamado particionado compuesto, nos permite combinar varios tipos de particionado. Por ejemplo, podemos particionar por rango (particionando por año, como hemos visto anteriormente), y subparticionar utilizando un hash interno para repartir los datos de forma equitativa entre las subparticiones.
Sin embargo, debemos tener en cuenta que las subparticiones están limietadas a particionado por hasho clave. Además, una tabla particionada por hash o clave no puede ser subparticionada.
Debemos recordar en este punto que podemos separar físicamente las subparticiones –al igual que lo haríamos con las particiones–, en distintos directorios, discos, etc…

¿Qué optimizaciones podemos realizar utilizando el particionado?

La optimización principal se conoce como poda (del inglés pruning). El concepto lo hemos explicado previamente, y se trata de realizar las búsquedas sólo en aquellas particiones de una tabla en la que sabemos que vamos a encontrar información que nos interesa.
El detalle más importante de este concepto es que esta poda se realiza de forma transparente para la aplicación (o usuario) que consulta la tabla, ya que no tendremos que especificar en qué particiones queremos buscar. Por el contrario, realizaremos una consulta a una tabla de forma “normal”, y el motor de MySQL ejecutará la consulta en las particiones adecuadas (dependiendo del método de particionamiento que tenga la tabla).
Referencias utilizadas:
Capítulo 17 del manual de MySQL.


En este video explican todos los tipos de particionamiento que existen y sobre todo con ejemplos. Altamente recomendable.



Ejemplo : 

CREATE TABLE IF NOT EXISTS `D_CALCULO` (
`id_calculo` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_bl_conte` int(11) NOT NULL DEFAULT '0',
`id_cliente` int(11) NOT NULL DEFAULT '0',
`factura` varchar(10) NOT NULL DEFAULT '0',
`id_usuario` int(3) NOT NULL DEFAULT '0',
`pago_realizado` decimal(10,2) NOT NULL DEFAULT '0.00',
`pago_pendiente` decimal(10,2) NOT NULL DEFAULT '0.00',
`pago_pendiente_iva` decimal(10,2) NOT NULL DEFAULT '0.00',
`st_tipo_calculo` char(1) NOT NULL DEFAULT '',
`dias_vig_tar1` int(8) NOT NULL DEFAULT '0',
`fecha_captura` date NOT NULL DEFAULT '0000-00-00',
PRIMARY KEY (`id_calculo`,`fecha_captura`),
KEY `idx_id_bl_conte` (`id_bl_conte`),
KEY `idx_id_cliente` (`id_cliente`)
)
ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=979829
PARTITION BY RANGE ( YEAR(fecha_captura) ) (
PARTITION p0 VALUES LESS THAN (2008) ENGINE=InnoDB,
PARTITION p1 VALUES LESS THAN (2009) ENGINE=InnoDB,
PARTITION p2 VALUES LESS THAN (2010) ENGINE=InnoDB,
PARTITION p3 VALUES LESS THAN MAXVALUE ENGINE=InnoDB
);

MySQL - Particionado de tablas para aumentar el rendimiento

Escrito por Carlos Chacin.

base de datosCon la aparición de la versión 5.1 de MySQL, se incluyó en éste el particionado de tablas (algo que en PostgreSQL ya existía hace tiempo) por lo que me he animado a escribir sobre el tema.

El particionado de tablas es una técnica que se usa para reducir la cantidad de lecturas físicas a la base de datos cuando ejecutamos consultas, existen dos principales modalidades de particionado: horizontal y vertical. ¡Vamos a los detalles!

Horizontal: Esta modalidad consiste en tener varias tablas con las mismas columnas en cada una de ellas y distribuir la cantidad de registros en estas tablas (generalmente se particiona separando la data por años, meses, etc). Ejemplo: tenemos tres tablas registro2001, registro2002, registro2003 y en cada tabla guardamos los registros de los años correspondientes, esto nos garantiza una mejora en el rendimiento considerable cuando realicemos consultas sobre las tablas ya que la data estará distribuida en tres partes y ya sabríamos dependiendo del año en cual tabla buscar.

Vertical: Esta modalidad generalmente la aplicamos en nuestros diseños de base de datos sin darnos cuenta, por ejemplo cuando tenemos una columna de tipo BLOB con una fotografía o un texto muy largo que no leemos frecuentemente y decidimos ponerla en otra tabla referenciandola con la clave foránea.

Ahora bien, el particionado horizontal es el que vamos a comentar, ya que el problema radica en cómo hacer para que nuestras aplicaciones sepan en que tabla guardar el registro dependiendo del año (porque obviamente no le vamos a agregar esas condiciones a nuestra aplicación); esto se logra agregando una serie de sentencias y condiciones en la definición de las tablas.

En los siguientes enlaces se muestra como hacerlo:

particiones para ySQL
particiones para PostgreSQL

En el ejemplo de MySQL se puede observar la gran diferencia de rendimiento con dos tablas que tienen exactamente la misma data (8 millones de registros), una sin particionar y la otra particionada por años. Al realizar una consulta filtrando por la columna en la cual se basó el particionado se obtuvieron los siguientes resultados:

Tabla sin particionado: 38.30 segundos
Tabla con particionado: 0.34 segundos

¡Asombroso nooo!

Fuente: www.dosideas.com/noticias/base-de-datos/576-incrementar-rendimiento-de-bbdd-con-qparticionado-de-tablasq.html

Tips: para MySQL – Buenos usos

1. Optimizando las consultas para usar el cache de consulta
La mayoría de los servers MySQL tienen habilitado el chache para consultas. Y esto es uno de los métodos más efectivos para mejorar el rendimiento, y es utilizado por el servidor de manera interna, por lo tanto cuando se utiliza de manera repetida, puede resultar en una mejora al realizar nuestras consultas.
El principal problema es que es invisible al programador, por lo tanto, se suele ignorar, cosa que no debe ser así, ya que podemos mejorar notablemente nuestras consultas a la base de datos.
Por ejemplo.
view plaincopy to clipboardprint?

// el cache de la consulta no funciona
$r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()");
// Lo recomendable es:
$today = date("Y-m-d");
$r = mysql_query("SELECT username FROM user WHERE signup_date >= '$today'");

La razón por la que el servidor no utiliza el cache, es porque usamos la función CURDATE(). Esto también es válido para funciones como NOW(), RAND(), etc…, porque simplemente el resultado de la función puede cambiar, MySQL decide deshabilitar el cache. Agregando solo una línea de PHP, antes de la consulta podemos solucionarlo y de esa manera mejoraremos nuestras consultas.

2. Usando EXPLAIN para tus consultas SELECT
Si usamos la keyword EXPLAIN podemos mejorar la forma en que MySQL puede ejecutar nuestra consulta. Esto puede ayudarnos a detectar los cuellos de botella y otros problemas con las consultas y la estructura de la tabla.
El resultado de una consulta EXPLAIN nos mostrará de que forma la indexación se usa, cuando la tabla comienza a escanearse y ordenarse, etc…
Tomar una consulta SELECT (preferiblemente una compleja con algún join), y agregar la palabra reservada(keyword) EXPLAIN delante de él, lo cual puedes usar PHPmyAdmin. Esto le mostrará como resultado una agradable tabla.

3. Usar LIMIT 1 cuando solo obtenemos un solo resultado.
Algunas veces cuando consultas tus tablas, ya sabes que vas a buscar un solo resultado. Podrías ser que busques un único registro o verificar la existencia de un cierto número de registros que satisfacen la condición WHERE.
En tal caso, agregar “LIMIT 1” a tus consultas puede incrementar la performance. De esta forma, el servidor dejará de escanear tales registros luego de encontrar 1, en vez de recorrer toda la tabla o índices.
Por ejemplo:
view plaincopy to clipboardprint?

// Lo que intuitivamente hacemos
$r = mysql_query("SELECT * FROM user WHERE state = 'Formosa'");
if (mysql_num_rows($r) > 0) {
// ...
}
// Lo que recomendable:
$r = mysql_query("SELECT 1 FROM user WHERE state = ‘Formosa' LIMIT 1");
if (mysql_num_rows($r) > 0) {
// ...
}



4. Indexar los campos de búsqueda
Indexar no solo la clave primaria o claves únicas. O sea, si existe alguna columna en la tabla que la utilizará para alguna búsqueda también deberías indexarla.
Esta regla también es válida para un string parcial donde usamos like por ej. “nombre LIKE ‘a%’”. Cuando buscamos desde el inicio del string, MySQL es capaz de utilizar el índice en la columna.
También es importante que tengas presente en que casos no puedes usar la indexación. De hecho, cuando buscas por una palabra (ej. “WHERE contenido LIKE ‘%algo%’”), no verás un beneficio con respecto a una indexación normal. Sin embargo si usas todo el texto mysql buscará o construirá su propia solución de indexación.


5. Indexar y usar el mismo tipo de columnas cuando hacemos JOINs.
Si tu aplicación contiene muchas consultas JOIN, necesitas asegurarte que la columna que vas a unir están indexadas en ambas tablas. Esto afecta como MySQL internamente optimiza la operación JOIN.
También, la columna que están unidas, necesitan ser del mismo tipo. De hecho, si unes una columna DECIMAL, a un columna INT desde otra tabla, MySQL habilitará para usar al menos una de los indexados. Aunque la codificación de los caracteres necesitan ser del mismo tipo para columnas tipo string.
view plaincopy to clipboardprint?

// Buscando Empresas de un pais
$r = mysql_query("SELECT company_name FROM users LEFT JOIN companies ON (users.state = companies.state) WHERE users.id = $user_id");
//Ambas columnas de paices deberían indexarse
//y ambos deberían tener el mismo tipo de codificación
// o MySQL puede hacer una búsqueda total de la tabla.



6. No usar ORDER BY RAND()
Esto es un de esos trucos que suenan lindo, y muchos programadores novatos caen en esta trampa. No sabes el terrible cuello de botella que puedes crear una vez que empiezas a usar esto en tus consultas.
Si necesitas filas al azar para tus resultados, hay otros buenas maneras de hacerlo. Por supuesto que se necesita de código adicional, pero hay garantía de que te evitaras un gran cuello de botella, a medida que tus datos crecen. El problema es que MySQL comenzará la operación RAND() (el cual necesita mas poder de procesamiento) por cada fila en la tabla antes de ordenarla y devolver solo 1 fila.
view plaincopy to clipboardprint?

// Lo que hay que evitar hacer
$r = mysql_query("SELECT nombre FROM usuario ORDER BY RAND() LIMIT 1");
// Optimizado:
$r = mysql_query("SELECT count(*) FROM usuario");
$d = mysql_fetch_row($r);
$rand = mt_rand(0,$d[0] - 1);
$r = mysql_query("SELECT nombre FROM usuario LIMIT $rand, 1");

Entonces, tomas un número aleatorio menor que el número de resultados y usas lo usas en tu clausula LIMIT.

7. Evitar usar SELECT *
La mayor parte de los datos lo lees desde la tabla, entonces tu consulta se hace lenta e incrementas el tiempo que toma en realizar la operación. Así, cuando el servidor de base de datos está separado del servidor web, tendrás mayor delay en realizar la transferencia entre ambos servidores.
Es un buen habito siempre especificar que columnas necesitas cuando haces un SELECT.
view plaincopy to clipboardprint?

// Lo que hacemos intuitivamente
$r = mysql_query("SELECT * FROM user WHERE user_id = 1");
$d = mysql_fetch_assoc($r);
echo "Welcome {$d['username']}";
// Lo Recomendable:
$r = mysql_query("SELECT username FROM user WHERE user_id = 1");
$d = mysql_fetch_assoc($r);
echo "Bienvenido {$d['username']}";
// Las diferencias son mayores con un grupo más grande de resultados.


8. Por lo menos debe haber un campo ID
En cada tabla hay una columna ID que es la PRIMARY KEY, AUTO_INCREMENT y generalmente INT. Asimismo preferentemente UNSIGNED, desde luego el valor no puede ser negativo.
Aún, si tienes una tabla de usuarios con un único campo de usuario, y esta no debe ser tu clave primaria, ya que los campos como VARCHAR, son muy lentos en las búsquedas y tendrás una mejor estructura en tu código referiendote a todos los usuarios con su id interno.
Existen también operaciones internas propias de MySQL, que usa internamente el campo de clave primaria. El cual es mas importante que configurar la base de datos.
Una posible excepción a la regla son las “tablas asociadas”, usadas por el tipo de asociación mucho-a-mucho entre 2 tablas. Por ejemplo una tabla “posts_tags” que contiene 2 columnas: post_id, tag_id el cual se usa para la relación entre las 2 tablas llamadas “post” y “tags”. Estas tablas pueden tener una PRIMARY_KEY que contiene ambos campos.

9. Mejor ENUM que VARCHAR
Las columnas del tipo ENUM son más rápidas y compactas. Internamente son almacenados como TINYINT, sin embargo pueden contener y mostrar valores string. Esto es ideal para ciertos campos.
Si tienes un campo, que contendrá solo un subconjunto de valores, es conveniente usar ENUM antes que VARCHAR. Por ejemplo, si tienes una columna llamada “estado”, solo contendrá los valores, “activo”, “inactivo”, “pendiente”, etc…
Existe una forma de conseguir una “sugerencia” por parte del mismo MySQL en como estructurar tu tabla. Cuando tienes un campo VARCHAR, puede sugerirte cambiar el tipo de la columna a ENUM. Esto lo realizas usando la llamada PROCEDURE ANALYSE().

10. Conseguir sugerencias con PROCEDURE ANALYSE()
PROCEDURE ANALYSE() le dirá a MySQL que analice la estructura de la columna y los datos actuales en tu tabla, lo cual lo hace con ciertas sugerencias para ti. Por supuesto, esto es útil si los datos de la tabla sean los actuales, porque tienen n rol fundamental en la decisión.
Por ejemplo, si creas un campo INT como clave primaria, pero sin embargo no tienes muchas filas, podrá sugerirte usar MEDIUMINT, o si estas usando un campo VARCHAR, podría sugerir convertirlo a ENUM, si solo hay valores únicos.
También puedes correr clickeando en “Proponer estructura de tabla” de phpMyAdmin, en la vista de tu tabla.
Ten presente que estas son solo sugerencias. Y si tu tabla va a crecer enormente, puede ser que no debas seguir estas sugerencias. La decisión es tuya, si es conveniente o no.

11. De ser posible utilizar NOT NULL
Al menos que tengas una razón específica para usar valores NULL, deberías siempre configurar tus columnas como NOT NULL.
Ante todo, debes preguntarte si hay alguna diferencia entre tener un valor string vacío o un valor NULL (para campos INT:0 vs NULL). Si no hay razón para tener ambas, no necesitas tener un campo NULL. Sabías que Oracle considera NULL y un string vacío como lo mismo?
Las columnas NULL requieren espacio adicional y pueden agregar complejidad a tus sentencias de comparación. Solo los ayuda cuando tu puedes. Sin embargo, entiendo que algunas personas deberían tener una razón específica, para incluir valores Nulos, el cual no es siempre malo.
De la documentación de MySQL:
“Las columnas NULL requieren un espacio adicional en la fila del registro si sus valores son NULL. Para tablas MyISAM, cada columna toma un bit extra, que ronda cerca del byte.

12. Preparando sentencias
Hay múltiples beneficios de usar sentencias preparadas, por razones de performance y seguridad.
Las Sentencias pre configuradas filtrará las variables que se unen a ellos por defecto, el cual es ideal para proteger tu aplicación contra ataques de inyección SQL. Puedes por supuesto filtrar tus variables manualmente, pero estos métodos son más propensos a errores humanos y olvido por parte del programador. Esto es al menos un problema menor cuando usas alguna clase de framework o ORM.
Dado que la atención se centra en el rendimiento, debería mencionar los beneficios en esta área, los cuales son mas significantes cuando la misma consulta comienza a usarse varias veces en la aplicación. Puedes asignar diferentes valores a la misma sentencia pre configurada, sin embargo MySQL solo tendrá que analizar una vez.
También en las últimas versiones de MySQL envía sentencias pre configuradas en forma binaria nativa, el cual es más eficiente y puede ayudar a reducir el delay de red.
Para usar sentencias pre configuradas en PHP puedes consultar la extensión mysqli o usar una base de datos con la capa de abstracción como la DOP.
view plaincopy to clipboardprint?

// Crear la sentencia preparada
if ($stmt = $mysqli->prepare("SELECT username FROM user WHERE state=?")) {
// unir parametros
$stmt->bind_param("s", $state);
// ejecutar
$stmt->execute();
// unir a una variable de resultado
$stmt->bind_result($username);
// buscar valores
$stmt->fetch();
printf("%s is from %s\n", $username, $state);
$stmt->close();
}


13. Consultas sin búfer
Normalmente cuando realizas una consulta desde un script, espera hasta que la ejecución finalice antes de continuar. Lo puedes cambiar usando consultas sin búfer.
Hayn una explicación extensa en la documentación de PHP para la función mysql_unbuffered_query():
“mysql_unbuffered_query() envia la consulta SQL a MySQL sin ir a buscar automáticamente y almacenar en búfer las filas resultantes como lo hace mysql_query(). Esto ahora una enorme cantidad de memoria con las consultas SQL que producen un gran número de resultados y puedes empezar a trabajar con los resultados inmediatamente luego de recuperar la primer fila ya que no tienes que esperar hasta que la consulta SQL se haya realizado.”
Sin embargo, esto tiene ciertas limitaciones. Tienes que leer todas las filas o llamar a mysql_free_result() antes de poder realizar otra consulta. Tampoco está permitido usar mysql_num_rows() o mysql_data_seek() en el conjunto de resultados.

14. Almacenar Direcciones IP como UNSIGNED INT
Muchos programadores crean un campo VARCHAR(15) sin darse cuenta que pueden almacenar direcciones IP como un valor entero. Con un INT puedes reducir a solo 4 bytes de espacio, y tener un campo de tamaño fijo en su lugar.
Tienes que asegurarte que tu columna es un UNSIGNED INT, porque la dirección IP usa todo el rango de un entero sin signo de 32 bit.
En tus consultas puedes usar el INET_ATON() para convertir una IP a entero, y INET_NTOA() en sentido contrario. Hay funciones similares en PHP llamadas ip2long() y log2ip().
view plaincopy to clipboardprint?

>$r = "UPDATE users SET ip = INET_ATON('{$_SERVER['REMOTE_ADDR']}') WHERE user_id = $user_id";


15. Tablas (estáticas) fijar la longitud son más rápidas
Cuando todas las columnas en una tabla son de “longitud-fija”, la tabla también es considerada “estática” o “long-fija”. Por ejemplo columnas que no son consideradas de longitud fija son: VARCHAR, TEXT, BLOB. Si incluyes solo 1 de estas columnas, la tabla deja de ser considerada de long-fija y tiene que ser tratada de forma diferente por el motor MySQL.
Las tablas de long-fija pueden mejorar su rendimiento porque el motor MySQL es más rápido al buscar a través de los registros. Cuando quiere leer una fila específica en la tabla, puede calcular rápidamente la posición. Si tiene una fila que no es de longitud fija, cada vez que hace una búsqueda, tiene que consultar el índice de la clave primaria.
También es más fácil para cachear y más fácil reconstruir luego de un accidente. Pero también pueden tener más espacio. Pero también, si conviertes un campo VARCHAR(20) a CHAR(20), tendrás siempre 20 bytes de espacio independientemente de que es lo que contenga.

16. Particionado Vertical
Particionado vertical es el acto de dividir la estructura de la tabla en forma vertical por razones de optimización.
Ejemplo 01: Podrías tener una tabla de usuarios que contiene “dirección”, que no se lee muy a menudo. Puedes elegir dividir la tabla y almacenar la información de la dirección en una tabla separada. De esa forma, la tabla de usuarios principal disminuirá de tamaño. Como es sabido, las tablas pequeñas funcionan más rápidas.
Ejemplo 02: si tienes una campo “ultimo_login” en tu tabla. Se actualiza cada vez que un usuario se loguea en tu página web. Pero cada actualización en la tabla causa que la cache de la tabla se actualice. Puedes poner el campo en otra tabla para actualizar la tabla de usuarios a un mínimo.
Pero también es necesario para asegurarse de que no necesitas contantemente unir estas 2 tablas luego del particionado o podrías sufrir una reducción de rendimiento.

17. Dividir grandes consultas DELETE o INSERT
Si necesitas realizar una gran consulta DELETE o INSERT en un sitio web, necesitas ser cuidados de no perturbar el tráfico de la web. Cuando una gran consulta como esa es realizada, puede bloquear tus tablas y parar la aplicación web.
Apache corre muchos hilos/procesos en paralelo. Por lo tanto trabaja más eficientemente cuando el script finaliza de ejecutarse tan pronto sea posible, para que los servidores no experimenten demasiadas conexiones y procesos abiertas a la vez que consumen recursos, especialmente memoria.
Si el bloqueo de tus tablas finaliza luego de un largo período de tiempo largo (como 30segundos o mas), en un sitio web de alto tráfico, puede causar un error, el cual puede tomas un período prolongado de tiempo para aclarar o aún peor, un accidente en tu sitio web.
Si tienes algún script de mantenimiento que necesita borrar un número grande de filas, solo use la cláusula LIMIT para hacerlo en lotes y así evitar una congestión.
view plaincopy to clipboardprint?

while (1) {
mysql_query("DELETE FROM logs WHERE log_date <= '2009-10-01' LIMIT 10000"); if (mysql_affected_rows() == 0) { // borrado listo break; } // incluso puede pausarlo un poco< usleep(50000); } 18. Las columnas pequeñas son más rápidas Con el motor de base de datos, el disco es tal vez el mayor cuello de botella. Conservar cosas pequeñas y mas compactas es usualmente una ayuda en términos de rendimiento para reducir la cantidad de transferencia. La documentación de MySQL tiene una lista de requerimientos de almacenamiento para todos los tipos de datos. Si se espera que una tabla tenga pocas filas, no hay razón para hacer una clave primaria como INT, en lugar de MEDIUMINT, SMALLINT o incluso en algunos casos TINYINT. Si no necesitas la variable tiempo, usar DATE en lugar de DATETIME. Solo asegúrese de dejar espacio razonable para crecer o podría terminar como Slashdot. 19. Elegir el motor correcto de almacenamiento Los dos motores principales en MySQL son MyISAM e InnoDB. Cada uno tiene sus pros y su contra. MyISAM es ideal para aplicaciones grandes lecturas, pero no es escalable cuando hay muchas escrituras. Incluso si acutalizas un campo de una fila, toda la tabla se bloquea, y ningún proceso puede leer de él hasta que la consulta finalice. InnoDB tiende a hacer un motor de almacenamiento más complicado y puede ser más lenta que MyISAM desde la mayoría de las aplicaciones pequeñas. Pero soporta bloqueo de filas, el cual es mejor escalable. Soporta también algunas de las más avanzadas características tales como transacciones. 20. Usar un Objeto Relacional Mapper Al usar un ORM (Objeto Ralacional Mapper), puedes ganar ciertos beneficios en performance. Todo lo que un ORM puede hacer, puede ser codificado manualmente también. Pero esto puede significar más trabajo extra y un alto nivel de experiencia. Los ORM son ideales para “Lectura lenta”. Esto es que puede recuperar valores solo cuando con necesarios. Pero hay que ser cuidadoso con ellos o puedes terminar creando demasiadas mini-consultas que pueden reducir el rendimiento. Los ORM pueden lotear sus consultas en las transacciones, el cual opera mucho más rápido que enviar consultas individuales a la base de datos. 21. Hay que ser cuidadoso con conexiones persistentes Conexiones persistentes significa reducir la sobrecarga de recrear conexiones a MySQL. Cuando una conexión persistente es creada, esta permanecerá aún cuando el script termine de correr. Dado que Apache rehúsa sus procesos hijos, la próxima el proceso corre como un nuevo script, y rehusará la misma conexión MySQL. mysql_pconnect() en PHP Suena fantástico en teoría. Pero puedes llegar a tener serios problemas con limitar las conexiones, el uso de la memoria y así sucesivamente. Apache corre en paralelo, y crea muchos procesos hijos. Esta es la principal razón que las conexiones persistentes no trabajan muy bien en este ambiente. Antes de considerar utilizar la función mysq_pconnect(), debes consultar con tu administrador de sistemas.

Fuente: http://todounblog.com.ar/tips-para-mysql-buenos-usos

Explain MySQL o cómo optimiza SQL

Fuente : http://www.sergiquinonero.net/explain-mysql-o-como-optimiza-sql.html

Hoy he tenido una interesante conversación con Marc Lladó i con José Mª Rodríguez (álias UTF8 ) sobre SQL y la optimización sql del mismo (en un entorno MySQL).

Al final se puede resumir que EXPLAIN MySQL es una herramienta indispensable (no la única) a la hora de realizar tareas de otpimización sql.

Explain MySQL no es más que una manera de mostrar como MySQL procesa las sentencias SQL mediante sus índices y uniones. El uso de Explain MySQL permite ayudar a los DBAs, en una primera instancia, a mejor el diseño de base de datos agregando índices y permitiendo una selección de consultas más óptimas.

Lo único que debemos hacer para hacer uso de Explain MySQL es anteponer “Explain” a la SQL deseada.

EXPLAIN SELECT * FROM `localidades` WHERE id =1
Ejecutando esta SQL, MySQL nos indica como la está procesando y nos mostrará un listado con información sobre índices, tablas, resultados, etc.

En el resultado de explain de mysql visualizaremos una tabla con 10 columnas de información para cada tabla implicada


De las columnas anteriores cabe destacar:
type: Esta columna indica el tipo de unión que se está usando (de más a menos óptimo).
const: Es la más óptima y se dá cuando la tabla tiene como máximo una fila que coincide. Como solo hay una fila coincidente, MySQL la considerará como constante por el optimizador.
eq_ref: Una fila será leída de la tabla A por cada combinación de fila de la tabla B. Este tipo es usada cuando todas las partes de un índice son usados para la consulta y el índice es UNIQUE o PRIMARY
ref: Todas las filas con valores en el índice que coincidan serán leídos desde esta tabla por cada combinación de filas de las tablas previas. Si la clave que es usada coincide sólo con pocas filas, esta unión es buena.
range: Sólo serán recuperadas las filas que estén en un rango dado, usando un índice para seleccionar las filas. La columna key indica que índice se usará, y el valor key_len contiene la parte más grande de la clave que fue usada. La columna ref será NULL para este tipo.
index: Este es el mismo que ALL, excepto que sólo el índice es escaneado. Este es usualmente más rápido que ALL, ya que el índice es usualmente de menor tamaño que la tabla completa.
ALL: Realiza un escaneo completo de tabla por cada combinación de filas de las tablas previas. Este caso es el peor de todos.
possible_keys: Esta columna indica los posibles índices a utilizar en la consulta
key: Esta columna indica el indice que MySQL actualmente está usando. Esta columna es NULL si no se ha elegido ninguno. Es interesante saber que podemos forzar a MySQL a usarlo (y también a ignorarlo) mediante el uso de FORCE INDEX, USE INDEX o IGNORE INDEX
key_len: El tamaño del índice usado. A menor valor mejor.
ref: La columna ref muestra que columna o constante es usada junto a la key para seleccionar las columnas de la tabla
rows: Indica el número de columnas que MySQL cree necesario examinar para ejecutar la SQL.
extra: Indica información adicional de como MySQL ha resuelto la SQL y hay que prestar atención si aparece USING FILESORT o USING TEMPORARY. En el primer caso, indica que MySQL debe hacer un paso extra para recuperar la información. En el segundo, MySQL necesita generar una tabla extra para mantener la información y después mostrarla y es típico al usar GROUP BY u ORDER BY.
En ocasiones, MySQL puede mostrar ALL en la columna type cuando:

La tabla es tan pequeña que MySQL ve más rapido hacer un escaneo completo de la tabla.
No hay restricciones usando las cláusulas ON o WHERE.
Se compara columnas indexadas con valores cosntantes
Las claves utilizadas devuelven muchos registros que coinciden con el valor.
Aún así, hay que decir que éste no es el único método de optimización SQL, aunque es uno bueno.

Para más información visita la referncia