Sie sind auf Seite 1von 13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net

PHP-Hispano.net
Comunidad hispana de desarrollo web
Inicio / Articulos / Diseo y uso de bases de datos relacionales

Diseo y uso de bases de datos relacionales


por Eloy8857
02 Jun 09

41953 lecturas

Artculo realizado por Eloy Bote Falc n para PHP-Hispano.net

ndice
Diseando la BD Normalizando la BD Normalizando la BD: primera forma normal (1FN) Normalizando la BD: segunda forma normal (2FN) Normalizando la BD: tercera forma normal (3FN) Diseando la BD sobre la marcha Consultando la BD: SELECT Consultando la BD: INNER JOIN Consultando la BD: LEFT JOIN Consultando la BD: GROUP BY Consultando la BD: optimizar consultas

PHP Web Form Gen


www.scriptcase.net

Rapid WEB application developme

Diseando la BD
Para disear una base de datos se parte de la recoleccin de atributos o campos que va a tener, y de la definicin de sus tipos de dato. La manera ms profesional es realizando el anlisis de requisitos con todas las personas que van a hacer uso de los datos. Pero por experiencia ya sabis que esto se hace muy a ojo: os piden realizar una aplicacin y segn los requisitos de la aplicacin hacis el diseo de la BD. El primer mtodo est ms estandarizado, y suele ser ms lento pero a cambio es improbable que el diseo salga mal. El segundo es ms rpido porque directamente se piensa en las tablas y sus datos sobre la marcha. Se utiliza principalmente en la metodologa de programacin conocida como "programacin extrema" y en las dems de la familia "desarrollo gil de software"; y es ms propenso a fallos de diseo , proporcionalmente inversos al tiempo que se dedique a su definicin y valoracin (ms tiempo, menos probabilidad de fallos).

Normalizando la BD
La normalizacin es un mtodo de anlisis de BD para c onseguir una BD relac ional, que respete la integridad referenc ial, y que no tenga redundanc ia de datos. Se divide en formas normales, y aunque hay un montn y es toda una ciencia, explicar por encima las 3 primeras ya que el nivel 3 es sufic iente para la mayora de casos. Hay que destacar que la normalizacin se puede hacer a nivel completo de la BD, o a nivel de tablas o esquemas. La tcnica es la misma: analizar el conjunto de campos y en base a eso designar una clave inicial que identifique a un grupo de datos. Por ejemplo si estamos normalizando todo un esquema de facturacin podemos partir de los datos del cliente aadiendo la clave del cliente, y segn vayamos normalizando nos saldrn todas las tablas y les iremos dando claves primarias nuevas. Si lo que normalizamos es una tabla, el procedimiento es el mismo y ya irn saliendo otras tablas subordinadas si acaso.

Las reglas de Codd


Adems de la normalizacin hay unas reglas, las reglas de Codd, que ay udan a disear una BD relac ional perfec ta (desde el punto de vista de Codd, claro) que merece la pena estudiarlas pues son c asi de lgic a c omn y nos harn la vida ms fcil en todos los sentidos. La idea de estas reglas surgi porque la normalizac in no era sufic iente para que una BD fuera relac ional, c onsistente e independiente . Hay ocasiones en las que los diseadores de las BD confeccionan la BD para satisfacer necesidades lgicas y funcionales de una aplicacin, por ejemplo almacenando los datos en un formato que luego la aplicacin se encarga de transformar. Esto es bastante tpico cuando el diseador es el programador de la aplicacin, y lo hace por comodidad o falta de conocimiento. La moraleja es que una BD debe ser independiente de la aplic ac in , y si lo pensis bien es mejor as. Segn las reglas de Codd la BD tiene que ser c ompletamente operativa desde su lenguaje de c onsultas (tpicamente SQL), y las restric c iones en los datos deben ser propiedad de la BD (no vale controlar la entrada desde la aplicacin). Con esto conseguiremos que mediante el SQL no se puedan realizar operaciones que hagan que la aplicacin no funcione (introduciendo datos en un formato inesperado para la aplicacin, por ejemplo), y entre otras cosas, que si tenemos que

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

1/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


realizar informes puntuales o sacar listados los podremos hacer desde un simple cliente y sin tener que parsear nada ni realizar consultas sobre consultas.

Normalizando la BD: primera forma normal (1FN)


Se podra decir que al aplicarla hay que asegurarse de que: No se permiten vec tores de c ampos en una c olumna Un ejemplo de esto es cuando en un campo de texto metemos varios valores del mismo dominio , como por ejemplo tres nmeros de telfono, o dos direcciones e-mail. Lo tpico en estos casos es separar los datos por comas, espacios u otro carcter y depus procesarlo mediante la aplicacin. Para evitar esto hay que definir una nueva tabla que tendr el identificador de la tabla de la que parte y el campo multivaluado, haciendo juntos de c lave nic a c ompuesta (se puede definir otra incremental si se desea, pero el conjunto de los otros dos campos tiene que ser nic o ). Adems en esta tabla se puede agregar campos que ayuden a describir el tipo de registro.

Ejemplo
Inc orrec to clientes IDCliente 45 275 Correc to clientes IDCliente 45 275 Nombre Francisco Miguel Nombre Francisco Miguel Telefono 444444444 555555555,666666666

telefonos_cliente IDCliente 45 275 275 Telefono 444444444 555555555 666666666

No se permiten grupos repetidos en varias c olumnas Esto es una variante de lo anterior: separamos los campos de un mismo dominio en varias columnas, haciendo un grupo difcilmente procesable a la hora de consultarlo. En el ejemplo anterior sera tener el campo telefono1, telefono2... y as. Es evidente que este fallo del diseo es incluso peor que el anterior pues habr muc hos c ampos nulos, y en caso de necesitar ms tendramos que redimensionar la tabla con un nuevo campo (telefono3). Pero la solucin es sencilla: la misma que en el anterior caso.

Ejemplo
Inc orrec to clientes IDCliente 45 275 Correc to clientes IDCliente 45 275 Nombre Francisco Miguel Nombre Francisco Miguel Telefono 444444444 555555555 Telefono2 NULL 666666666 Telefono3 NULL NULL

telefonos_cliente IDCliente 45 275 275 Telefono 444444444 555555555 666666666

No se permiten c ampos nulos Esta regla es algo discutible, pero tiene su lgica. Para empezar, si un campo va a tener valores nulos, qu proporcin de registros tendrn

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

2/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


ese campo con valor nulo? En mi opinin esta regla nos ayuda a separar unas entidades de otras, porque si una cantidad de registros tienen unos atributos que otros no, no ser que pertenecen a otra c lase ? Por ejemplo, si en una tabla de productos definimos los campos talla, kilates y potencia se ve que los productos tendrn clases diversas y entonces habr que crear una entidad para c ada c lase (ropas, joya y elctricos, por ejemplo) construyendo lo que se llama una generalizac in .

Ejemplo
Inc orrec to productos IDProducto 147 155 221 Correc to productos IDProducto 147 155 221 ropas IDProducto 147 joyas IDProducto 155 electricos IDProducto 221 Potencia 1500 Kilates 24 Talla 44 Nombre Blusa fashion Broche duquesa Subwoofer extreme Nombre Blusa fashion Broche duquesa Subwoofer extreme Talla 44 NULL NULL Kilates NULL 24 NULL Potencia NULL NULL 1500

Normalizando la BD: segunda forma normal (2FN)


Una tabla est en segunda forma normal siempre que est en primera forma normal y todos sus atributos (campos) dependan totalmente de la c lave c andidate sin ser parte de ella. Viene a ser que, si un campo de la tabla no depende totalmente de una clave nica (que pueden ser compuestas), debe sacarse fuera con la parte de la clave principal de la que es dependiente.

Ejemplo
Inc orrec to lineas_pedido IDCliente 29 46 204 144 Correc to lineas_pedido IDCliente 29 46 204 144 productos IDProducto 9 Nombre_producto Baln reglamentario de baloncesto IDProducto 42 9 42 10 Cantidad 1 5 1 1 IDProducto 42 9 42 10 Cantidad Nombre_producto 1 5 1 1 Zapatillas deportivas de tenis Baln reglamentario de baloncesto Zapatillas deportivas de tenis Zapatillas deportivas de rugby

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

3/13

26/09/13
10 42

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


Zapatillas deportivas de rugby Zapatillas deportivas de tenis

Como vemos en la tabla "lineas_pedido" del ejemplo incorrecto, la nica clave candidata es IDCliente + IDProducto, ya que en c onjunto son nic as en la tabla (podramos tener un IDLinea_pedido nico tambin, pero an as esos dos campos seguran siendo una clave candidata). El campo Cantidad es dependiente de la clave candidata, pues el cliente ha pedido de ese producto una cantidad determinada de artculos, pero el nombre en cambio es dependiente slo del produc to, no del c liente . Si dejaramos esa tabla como est, tendramos por una parte una redundanc ia de datos innec esaria pues el nombre del producto lo podemos sacar uniendo la tabla de productos, y adems podran darse inc onsistenc ias de datos si cambiamos el nombre del producto en un registro... cul sera el nombre real del producto 42 si en varios registros tiene un nombre distinto?

Conclusiones
Por lo tanto los pasos para aplicar la segunda forma normal son muy sencillos: enc ontrar las c laves c andidatas (compuestas), que identifican de manera nica el registro; comprobar que los campos que no forman parte de la clave candidata y no son parte de ella (en el ejemplo de antes ni IDCliente ni IDProducto deben ser analizados) dependen totalmente de la c lave c andidata. Para el segundo paso puede ayudar preguntarse lo siguiente: puedo saber el valor del campo X sabiendo el valor del campo Y (siendo Y parte de la clave candidata y X no siendo parte de ella)? Pero como todo lo relacionado con el anlisis esto requiere un mnimo de agudeza, pues puede que casualmente el valor de un campo se repita para una parte de la clave (por casualidad todos los que compran unas pelotas de tenis lo hacen en cantidades de 5) pero sabemos que no es dependiente de ella. Por ltimo, aclarar que hay ocasiones en las que el anlisis no tiene que ser tan c errado , ya que a veces las apariencias engaan. Un ejemplo de ello es una tabla de facturas que tiene el nombre, direccin, NIF, y dems datos del cliente: a simple vista esos datos estn duplic ados y dependen del c liente y no de la fac tura, pero resulta que esos datos deben permanecer ah pues fiscalmente debemos saber a qu datos se emiti una factura; esos datos son realmente dependientes de la fac tura, no del c liente . Si no los incluyramos en la tabla de facturas, al modificar el registro del cliente en la tabla de clientes no sabramos a qu datos fiscales se emiti la factura. As que una vez ms, hay que utilizar un poco de ingenio y no aplic ar normas c omo una mquina y sin pensar.

Normalizando la BD: tercera forma normal (3FN)


Una tabla est en tercera forma normal siempre que est en segunda forma normal (y por consiguiente en primera) y todos sus campos no primarios (campos que no forman parte de una clave candidata) dependen nic amente de la c lave c andidata. Suena como la segunda forma normal, pero es muy distinta: ningn c ampo que no sea parte de la c lave c andidata puede depender de otro c ampo que no sea la c lave c andidata.

Ejemplo
Inc orrec to carga_diaria IDServidor 21 21 21 34 34 34 66 66 66 Correc to carga_diaria IDServidor 21 21 21 34 34 34 66 66 66 servicios Fecha 2009-01-14 2009-01-15 2009-01-16 2009-01-14 2009-01-15 2009-01-16 2009-01-14 2009-01-15 2009-01-16 IDServicio 1 9 22 3 22 22 9 22 1 Carga 100 100 85 74 58 67 98 94 84 Fecha 2009-01-14 2009-01-15 2009-01-16 2009-01-14 2009-01-15 2009-01-16 2009-01-14 2009-01-15 2009-01-16 IDServicio 1 9 22 3 22 22 9 22 1 Nombre_servicio Oracle MySQL Apache PostgreSQL Apache Apache MySQL Apache Oracle 10g Carga 100 100 85 74 58 67 98 94 84

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

4/13

26/09/13
IDServicio 1 9 22 3 22 22 9 22 1 Nombre_servicio Oracle MySQL Apache PostgreSQL Apache Apache MySQL Apache Oracle 10g

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net

Imaginad que una tabla se encarga de registrar el primer servicio que ms carga los servidores cada da. Del ejemplo incorrecto deducimos que el IDServidor y la Fecha son la clave candidata, pues identific an de manera nic a los registros. Analizando vemos que el IDServicio, que no es un campo primario, depende nicamente de la clave candidata, y que la carga tambin. Pero resulta que el Nombre_servicio depende de esa clave candidata pero tambin depende del IDServicio, pues c on el IDServic io podemos averiguar qu Nombre_servic io tiene el registro . Para solucionar esto sacamos el campo Nombre_ servicio de la tabla, y nos llevamos el IDServic io para que sea la clave principal pues es el c ampo del que depende . Y con este ejemplo vemos qu fcil es librarnos de las inconsistencias de no cumplir la tercera forma normal, y de la redundancia de datos. Si no hubieramos normalizado tendramos que en un registro el IDServicio 22 es Apache y nadie nos asegura que en otro el IDServicio 22 tambin lo sea pues puede haberse modificado el campo Nombre_servicio. Y si resulta que la tabla fuese un histrico de 500 servidores durante 1000 das, tendramos 500 mil registros con un c ampo innec esario que estara duplic ado muchsimas veces.

Diseando la BD sobre la marcha


Si en vuestro desempeo habitual del trabajo os encontris con que no podis aplicar, de una manera formal y detallada, la normalizacin a la hora de disear BD, no os alarmis pues le pasa a mucha gente. Lo que puede ocurrir es que nos quede una BD no relacional, y eso es siempre negativo, pero a base de experiencia iris adquiriendo una soltura y c apac idad analtic a automtic as. La normalizacin, al basarse en reglas lgicas, se puede memorizar muy fcilmente y al final forma parte del instinto del diseador: no necesitaris bolgrafo y papel para ver que una tabla no est normalizada. De hecho cuando sepis que datos necesita la aplicacin pensaris directamente en las tablas que saldrn.

Primero, documentarse
Lo ms importante para disear la BD sobre la marcha es tener la mente amplia, c onoc er las bases de la normalizac in, y dejarse ac onsejar por los expertos. Todo esto de las BD relacionales no es nuevo y hay muchos gurs (Codd, Edgar Frank Codd, es el padre de todos) que os pueden ayudar a entender qu caractersticas debe cumplir una BD para ser relacional. De modo que si no sabis del tema, lo mejor es que os olvidis de las malas enseanazas que tengis imbuidas: una BD con muchas tablas no est mal diseada (una con pocas es ms probable que s lo est); llevarse el cdigo del cliente a todas las tablas (lo necesiten o no) no es la forma de tener una BD relac ional; guardar los datos serializados en un campo no te hac e la vida ms fc il; tener un campo que hace referencia a una tabla unas veces y a otra en otras ocasiones no es un buen diseo (un c ampo referenc ial slo puede referenc iar a una tabla, as que usad la generalizacin en esas situaciones).

Errores habituales
Un error habitual a la hora de usar este mtodo de diseo es tener un campo referencial que admite valores nulos o vacos (tpico clave_referencia 0 cuando no referencia a nada). Si la BD es relacional, un c ampo referenc ial tiene que apuntar a otro registro en la BD. A veces tenemos un campo IDPadre que hace referencia a un mismo registro de la tabla, o vale 0 cuando el registro es padre en s... pero lo c orrec to en una relac in reflexiva (una tabla relacionada consigo misma) que da lugar a otro tabla que contiene el IDHijo y el IDPadre; consultando esa tabla podemos saber si un registro es hijo (tiene entradas con su ID en IDHijo) o padre (su ID est en algn IDPadre) y sacar todos los hijos de un padre.

Consejos
Otro buen consejo, que no est limitado a este mtodo de disear, es tener en c uenta el tamao de las tablas en cuanto a longitud de fila (en bytes). De hecho recuerdo que me hablaron de una regla de diseo de BD que deca que una tabla no deba contener ms de X campos... y bueno, siempre es discutible pero es ms ptimo que la longitud de la fila no sea muy larga, sobre todo en las tablas que se c onsultan c on frec uenc ia. Es una prctica muy recomendada que si tenemos campos grandes, tipo TEXT o BLOB, saquemos esos datos a otra tabla para que las bsquedas y JOIN generales que no necesiten ese campo sean ms rpidas. Hay que tener en cuenta que el sistema de gestin de BD (SGBD) en ocasiones no puede optimizar las consultas y necesita esc anear por c ompleto la tabla, o tiene que volcarla a la memoria fsica o virtual. En definitiva: recordad que una BD relacional no puede ser dependiente de la aplic ac in , sino al revs. As que olvidaros de disearla pensando qu es lo mejor para la aplicacin, y pensad qu es lo c orrec to para que sea ms ptima y senc illa de manejar independientemente del cliente que la maneje (aplicacin, consultas directas, herramientas de informe...).

Consultando la BD: SELECT


En este apartado voy a explicar las consultas simples en SQL. La forma bsica de un SELECT es:

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

5/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


S E L E C T[ o p c i o n e s ]v a l o r e sF R O Mt a b l a sW H E R Ec o n d i c i o n e s[ O R D E RB Yc a m p o s ]

Analizando la sintxis tenemos opc iones: segn el SGBD que usemos tendremos opciones para establecer la prioridad de la consulta, obtener resultados no duplicados, y opciones tiles como el SQL_CALC_FOUND_ROWS de MySQL, que calcula cantos registros devuelve la consulta sin aplicarle un LIMIT (as podemos obtener por ejemplo 20 registros, ideal para una paginacin, y saber cuntos registros devolvera sin el LIMIT lanzando despus un SELECT FOUND_ROWS()). valores: son las columnas con valores que devolver la consulta. Aqu podemos indicar de todo: nombres de campos, operaciones aritmticas, valores constantes, funciones, subconsultas... y tambin as, podemos asignarles un alias para que se devuelvan con ese nombre de columna ("SELECT campo1 c1 FROM tabla" nos devolvera el campo1 con el nombre de columna c1). En los alias, dependiendo del SGBD, se puede usar el keyword opcional AS, que es algo ms claro a la vista: SELECT campo1 AS c1 FROM tabla tablas: aqu van todas las tablas que participarn en la consulta. Pueden ir tanto tablas (y vistas), como subconsultas, y se pueden usar alias tambin (el keyword AS es menos soportado aqu, ya que por ejemplo Oracle no lo admite). Una subconsulta significa poner una consulta entre parntesis y usar su resultado como una tabla normal:

S E L E C Tc a m p o 1 ,s c 1 ,s c 2F R O Mt a b l a ,( S E L E C Tc a m p o 2A Ss c 1 ,c a m p o 2A Ss c 2F R O Mt a b l a 2 )W H E R E c a m p o 1=s c 1

Algunos SGBD como MySQL permiten varias opciones en este parte, como indicar qu ndice queremos que se use para recorrer la tabla. Esto ltimo es muy raramente til pues el optimizador de c onsultas no suele errar en el ndic e a usar; es ms comn que se equivoque en el orden en el que une las tablas, pero para eso hay opciones como STRAIGHT_JOIN en el SELECT que obligan al optimizador a unir las tablas en el orden en el que las hemos puesto nosotros. Las JOIN van en este lugar tambin pero ms adelante las veremos. c ondic iones: serie de condiciones que en conjunto tienen que evaluar a TRUE para que el registro sea devuelto. Debido al orden en que se procesan las consultas, aqu no se pueden usar los alias de los c ampos que hayamos indicado en la parte de "valores" (pero s los alias de tablas), as que tenemos que usar el nombre del campo o poner de nuevo la operacin entera si se trata de una operacin. Son estndares expresiones como IS NULL/IS NOT NULL (devuelve TRUE si lo evaluado es/no es nulo), NOT (niega la expresin, de modo que si evala a TRUE no ser devuelto el registro), BETWEEN valor1 AND valor2 (el operando precedente tiene que estar entre los valores indicados, inclusive), LIKE 'patrn' (el operando, que debe ser una cadena, debe coincidir con el patrn, que admite, comodines como el '%' para cualquier carcter de 0 a N veces y el '_' para cualquier carcter una sola vez)... y como no, tambin podemos usar funciones del SGBD y operaciones de cualquier tipo, adems de los operadores >, >=, <>, <, <=. Como operadores lgicos tenemos el NOT, AND y OR (con ese orden de preferencia), y para no marearnos en las expresiones complicadas podemos meter entre parntesis las expresiones:

. . .W H E R E( c o n d i c i o n 1O Rc o n d i c i o n 2 )A N Dc o n d i c i o n 3A N Dc o n d i c i o n 4

Aqu es donde filtraremos los resultados para obtener lo que nos interese , como los usuarios que tienen el nombre Miguel, los trabajadores que tienen ms de 30 aos, las lneas de pedido de un pedido concreto... ORDER BY : aqu especificamos el orden de los registros segun el campo que queramos. Aqu s se puede usar alias de c ampos, o el nmero de posicin que ocupa el valor dentro de la fila:

S E L E C Tc a m p o 1A Sc 1 ,c a m p o 2F R O Mt a b l aO R D E RB Y2

En el ejemplo anterior se ordenaran los registros por campo2, que es la columna nmero 2 del resultado Tambin se puede ordenar por varios campos, y en ascendente o descendente:

. . .O R D E RB Yc a m p o 1D E S C ,c a m p o 2A S C

El ORDER BY en ocasiones puede hac er que el resultado tarde ms en ser devuelto pues el SGBD puede necesitar realizar otra pasada para ordenarlo.

Limitando el nmero de registros devueltos


Es frecuente que al consultar queramos obtener un nmero mximo de registros, por ejemplo para realizar una paginacin o simplemente porque queremos obtener el ltimo registro insertado y no queremos andar con consultas complejas para sacarlo. Todos los SGBD tienen su mtodo para realizar esto: MySQL tiene el LIMIT (haciendo SELECT * FROM tabla WHERE ... ORDER BY ... LIMIT [10 | 5, 10] obtendramos los 10 primeros registros o los 10 registros a partir del nmero 5 con la segunda sintaxis), MSSQL Server tiene el TOP (con SELECT TOP 10 ... FROM tabla sacaramos los 10 primeros registros), Oracle usa el ROW_NUMBER (mediante subconsultas; es un sistema bastante ms incmodo

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

6/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


que los dems, pero es ms estndar), PostgreSQL usa tambin LIMIT (LIMIT 10 OFFSET 5)... El mtodo ms estndar es mediante cursores pero no todos los SGBD siguen las directrices del ISO SQL.

Consultando la BD: INNER JOIN

S E L E C T. . .F R O Mt a b l a 1I N N E RJ O I Nt a b l a 2O Nt a b l a 1 . c a m p o=t a b l a 2 . c a m p oW H E R E. . .

Cuando realizamos una INNER JOIN lo que hacemos es unir dos tablas mediante una o varias c ondic iones, habitualmente porque estn relac ionadas por un c ampo c lave . Se pueden concatenar tantas JOIN como queramos; de hecho es la manera habitual de seguir las relac iones de las tablas al realizar consultas (una tabla se relaciona con otra, que a su vez se relaciona con otra...). INNER JOIN es exc lusivo , de modo que la relacin debe c umplirse siempre o sino no se devolver el registro. As, si consultamos todos los clientes y unimos los pedidos mediante el ID de cliente obtendremos slo los que tengan pedidos. Si hacemos:

S E L E C Tc a m p o 1F R O Mt a b l atI N N E RJ O I Nt a b l a 2t 2O Nt . i d=t 2 . i d _ t

sera lo mismo que hacer:

S E L E C Tc a m p o 1F R O Mt a b l at ,t a b l a 2t 2W H E R Et . i d=t 2 . i d _ t

De hecho, los optimizadores de consultas (query optimizer) suelen cambiar las JOINS por consultas as. No es que sea ms ptimo realizarlo as, pero para operar sobre las tablas para optimizar la consulta se manejarn mejor as. Pero del lado del programador de BD, es ms fc il de ver las uniones mediante JOINs que mirando las tablas del FROM y luego las condiciones del WHERE (al menos para m).

Las condiciones del JOIN (el ON ...)


Cabe destacar que en la condicin del JOIN se puede esc ribir c ualquier tipo de expresin que evale a TRUE (o a FALSE, aunque en ese caso no se devolver el registro): podemos usar LIKE, operaciones aritmticas, operadores >, =... pero no es recomendable pues por razones que el optimizador sabr suele ser ms lento que si las hubiramos puesto en el WHERE. Por lo tanto:

S E L E C Tc a m p o 1F R O Mt a b l atI N N E RJ O I Nt a b l a 2t 2O Nt . i d=t 2 . i d _ tA N Dt . c a m p o 2>t 2 . c a m p o 2

es mejor traducirlo a:

S E L E C Tc a m p o 1F R O Mt a b l atI N N E RJ O I Nt a b l a 2t 2O Nt . i d=t 2 . i d _ tW H E R Et . c a m p o 2>t 2 . c a m p o 2

Por lo dems, c ualquier c ondic in que no sea ligar las tablas por ID es mejor ponerla en el W HERE. Tambin se puede omitir el ON con la condicin, pero en ese caso el resultado ser en la mayora de los casos catastrfico, pues si usamos 2 tablas sin relac ionarlas se realizar el produc to c artesiano entre ellas, o sea que por cada registro de la tabla 1 se devolvern todos los registros de la tabla 2. Si son tablas de 10 y 5 registros no es mucho problema, se devolveran 50 registros, pero si son de 10000 y 50000..., adems no slo ser un resultado grande, tambin muy lento y pesado en recursos para el servidor de BD.

Rendimiento de las JOIN: no olvidarse de las claves


Y por ltimo, el rendimiento de las JOIN. Es conveniente realizar la JOIN mediante campos que sean claves (primarias, candidatas, externas...) pues el SGBD recorrer las tablas para satisfacer las condiciones de la JOIN, y si se usan ndic es el rec orrido es infintamente ms rpido . As que es importante que todo campo referencial, que son los que se usan para unir las tablas en las consultas, sean claves.

Ejemplo
Vamos a suponer una BD con clientes, pedidos y productos (1 cliente tiene N pedidos, 1 pedido es de un nico cliente, y 1 pedido tiene N productos que a su vez pueden estar en M pedidos). De la relacin pedidos - productos nos sale la entidad lineas_pedidos.

c l i e n t e s>p e d i d o s>l i n e a s _ p e d i d o< -p r o d u c t o s

Tabla clientes: id_cliente nombre

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

7/13

26/09/13
2 10 13 John Edward Rose

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net

Tabla pedidos: id_pedido 1 2 3 4 5 6 7 8 9 id_cliente 2 2 10 2 10 10 10 2 10 fecha 2009-01-24 08:00:15 2009-01-24 09:22:08 2009-01-27 13:10:22 2009-01-27 17:54:15 2009-01-29 08:13:01 2009-01-29 10:28:57 2009-01-29 18:26:59 2009-01-30 12:30:47 2009-01-30 12:31:18

Tabla productos: id_producto 1 2 3 4 5 nombre frigorfico ACME televisor plasma minicadena HI-FI aspirador ACME climatizador ACME precio_base 749.00 799.00 129.00 89.00 1499.00 stock 25 87 19 28 32

Tabla lineas_pedido: id_pedido 1 1 2 3 4 4 4 5 6 7 8 9 id_producto 1 4 2 2 2 3 4 2 5 4 2 5 precio_unidad cantidad 709.00 89.00 729.00 699.00 729.00 129.00 89.00 699.00 1399.00 89.00 729.00 1399.00 1 2 1 1 1 1 2 7 9 5 1 8

S E L E C T*F R O Mc l i e n t e scI N N E RJ O I Np e d i d o spO Nc . i d _ c l i e n t e=p . i d _ c l i e n t e

id_cliente 2 2 10 2 10 10 10 2 10

nombre John John

id_pedido 1 2

fecha 2009-01-24 08:00:15 2009-01-24 09:22:08 2009-01-27 13:10:22 2009-01-27 17:54:15 2009-01-29 08:13:01 2009-01-29 10:28:57 2009-01-29 18:26:59 2009-01-30 12:30:47 2009-01-30 12:31:18

Edward 3 John 4

Edward 5 Edward 6 Edward 7 John 8

Edward 9

Como se puede observar no se han devuelto registros del cliente 13 porque no tiene pedidos. Y tambin se ve que por cada cliente se han devuelto tantos registros como coincidencias tiene en la tabla de pedidos. Si quiseramos obtener slo un registro por cliente usaramos GROUP BY para

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

8/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


agrupar los registros, pero eso lo veremos ms adelante.

S E L E C Tp r . n o m b r e ,l . p r e c i o _ u n i d a d ,l . c a n t i d a d ,( l . p r e c i o _ u n i d a d*l . c a n t i d a d )A St o t a l _ l i n e a , R O U N D ( 1 0 0-( ( l . p r e c i o _ u n i d a d*1 0 0 )/p r . p r e c i o _ b a s e ) ,2 )A Sd e s c u e n t o F R O Mp e d i d o spI N N E RJ O I Nl i n e a s _ p e d i d olO Np . i d _ p e d i d o=l . i d _ p e d i d o I N N E RJ O I Np r o d u c t o sp rO Nl . i d _ p r o d u c t o=p r . i d _ p r o d u c t o W H E R Ep . i d _ c l i e n t e=2A N Dp . i d _ p e d i d o=4

nombre televisor plasma minicadena HI-FI aspirador ACME

precio_unidad cantidad total_linea 729.00 129.00 89.00 1 1 2 729.00 129.00 178.00

descuento 8.76 0.00 0.00

Lo que hemos hecho ahora es, dado un cliente y un pedido (para asegurarnos de que el pedido es de un cliente en concreto), sacar el detalle de los produc tos solicitados en dicho pedido. As podramos preparar el detalle de la fac tura con el nombre del producto, su precio, su cantidad, su precio total y el % de descuento que ha tenido sobre el precio base.

Consultando la BD: LEFT JOIN

S E L E C T. . .F R O Mt a b l a 1L E F TJ O I Nt a b l a 2O Nt a b l a 1 . c a m p o=t a b l a 2 . c a m p oW H E R E. . .

La sintaxis de LEFT JOIN es idntica a INNER JOIN, pero su comportamiento es muy distinto. Con LEFT JOIN obtenemos todos los registros de la izquierda de la expresin ("tabla1" en el ejemplo de arriba) y luego se uniran c on la parte derec ha, si hubiera c oinc idenc ias. Por ejemplo, si unimos clientes con pedidos y un cliente no tiene pedidos, se devolvera el cliente en el resultado pero con todos los campos de la tabla pedidos a NULL. As es muy fcil obtener todos los clientes que no tienen pedidos:

S E L E C T. . .F R O Mc l i e n t e scL E F TJ O I Np e d i d o spO Nc . i d _ c l i e n t e=p . i d _ c l i e n t eW H E R Ep . c a m p oI S N U L L

Por lo dems la LEFT JOIN tiene las mismas caractersticas que una INNER JOIN en cuanto a las condiciones que se pueden poner en el ON, y opciones que el SGBD permita.

La variante RIGHT JOIN


Hay una variante no estndar de LEFT JOIN, la RIGHT JOIN, que hace exactamente lo mismo pero devolviendo todos los registros de la derec ha de la expresin . Al no ser estndar y ser perfectamente sustituible por la LEFT JOIN (lo nico que cambia es el orden en el que pongamos las tablas) no se rec omienda usarla.

Ejemplo
Tabla clientes: id_cliente 2 10 13 nombre John Edward Rose

Tabla pedidos: id_pedido 1 2 3 4 5 6 7 8 9 id_cliente 2 2 10 2 10 10 10 2 10 fecha 2009-01-24 08:00:15 2009-01-24 09:22:08 2009-01-27 13:10:22 2009-01-27 17:54:15 2009-01-29 08:13:01 2009-01-29 10:28:57 2009-01-29 18:26:59 2009-01-30 12:30:47 2009-01-30 12:31:18

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

9/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


S E L E C T*F R O Mc l i e n t e scL E F TJ O I Np e d i d o spO Nc . i d _ c l i e n t e=p . i d _ c l i e n t e

id_cliente 2 2 10 2 10 10 10 2 10 13

nombre John John

id_pedido 1 2

fecha 2009-01-24 08:00:15 2009-01-24 09:22:08 2009-01-27 13:10:22 2009-01-27 17:54:15 2009-01-29 08:13:01 2009-01-29 10:28:57 2009-01-29 18:26:59 2009-01-30 12:30:47 2009-01-30 12:31:18 NULL

Edward 3 John 4

Edward 5 Edward 6 Edward 7 John 8

Edward 9 Rose NULL

A diferencia del INNER JOIN, hemos obtenido tambin un registro del cliente 13 aunque no tiene coincidencias en la tabla de pedidos. Ahora, para obtener los clientes que no tienen pedidos simplemente hacemos:

S E L E C T*F R O Mc l i e n t e scL E F TJ O I Np e d i d o spO Nc . i d _ c l i e n t e=p . i d _ c l i e n t eW H E R Ep . i d _ p e d i d oI S N U L L

id_cliente 13

nombre Rose

id_pedido NULL

fecha NULL

Consultando la BD: GROUP BY

S E L E C T. . .F R O Mt a b l a 1I N N E RJ O I Nt a b l a 2O Nt a b l a 1 . c a m p o=t a b l a 2 . c a m p oW H E R E. . .G R O U PB Yc a m p o 1 [ H A V I N Gc o n d i c i o n e s ]

Con GROUP BY podemos agrupar, en torno a uno o varios c ampos (algunos SGBD admiten alias en vez de campos), los registros devueltos. Opcionalmente podemos usar condiciones del agrupamiento en el HAVING, algo tpicamente usado con las funciones de agregado.

Funciones de agregado (COUNT, SUM, MAX, AVG...)


Cuando agrupamos los registros (no hay por qu usar JOINs, se puede hacer con una sola tabla) podemos usar las funciones de agregado (COUNT para contar registros, SUM para sumar valores de un campo, MAX para obtener el valor mximo del campo, AVG para obtener el valor promedio del campo...) en el SELECT y en el HAVING. Si slo usamos una funcin de agreagado en el SELECT, no es obligatorio usar GROUP BY, pero si adems de eso indicamos que se devuelva un campo, el SGBD no lo permitir y devolver un error. As, podemos hacer:

S E L E C TC O U N T ( * )F R O Mt a b l a

pero no:

S E L E C TC O U N T ( * ) ,c a m p o 1F R O Mt a b l a

Es algo ilgico que se pueda usar una funcin de agregado sin agrupar, pero lo que ocurre es que por simplic idad los SGBD lo permiten para cuando se quiere obtener el nmero de registros, o el valor mayor de un campo, cosas bastante frecuentes. En estos casos es el propio SGBD el que se enc arga de agrupar y generalmente de optimizar estas c onsultas. Pero cuidado con el parmetro que ponemos en las funciones de agregado, porque si indicamos un valor que sea nulo no se aplicar; y tened en cuenta que COUNT(*) es una exc epc in , pues * no es ningn campo o valor, pero los SGBD lo admiten como atajo para simplemente contar todos los registros de la consulta... no intentis hacer SUM(*) porque eso fallar.

Filtrando los grupos con HAVING


Junto con las funciones de agregado es habitual usar el HAVING para obtener, de los grupos de registros devueltos, los que c umplan una o varias c ondic iones: obtener los clientes que han facturado ms de 60000 euros en un ao, los que han realizado ms de 20 pedidos en un mes, los que su media de importe de pedidos es superior a 1000 euros... En el HAVING se puede poner c ualquier tipo de c ondic in , incluso las que pueden ir en el WHERE, pero es muy recomendable que si una c ondic in puede ir en el W HERE vay a en el W HERE, pues esas condiciones se usan en la optimizacin para recorrer ms rpido los registros

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

10/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


implicados; el HAVING, debido al orden de procesamiento de una consulta, se ejec uta c asi al final del todo . El orden de procesamiento de una consulta suele ser: se unen y filtran las tablas implicadas (mediante las condiciones WHERE y las ON de las JOIN), se aplica el GROUP BY si lo hubiera (en este punto algunos SGBD ya saben qu alias hemos asignado a los valores del SELECT y nos permiten usarlos) y el HAVING si tambin lo hubiera (algunos SGBD tambin permiten usar alias aqu) y finalmente se aplica el ORDER BY. Huelga decir que los optimizadores de consultas tienen mucho que decir en estos pasos, pues a vec es no nec esitan ordenar el resultado , otras veces tienen que repasar el resultado de nuevo para ordenarlo ...

Ejemplo
Tabla clientes: id_cliente 2 10 13 nombre John Edward Rose

Ahora vamos a aadir el importe del pedido a la tabla de pedidos. El importe de un pedido es, generalmente, propiedad del pedido pues la suma de los productos que contiene podra variar y el precio del pedido no debera variar. Es discutible pues se puede argumentar que el cambio de precio de uno de los productos que pidi el cliente no debe implicar el cambio del precio del pedido, y tambin se puede argumentar que si se considera inviolable el precio de un pedido tambin lo tienen que ser los precios de los productos que contiene. id_pedido 1 2 3 4 5 6 7 8 9 id_cliente 2 2 10 2 10 10 10 2 10 fecha 2009-01-24 08:00:15 2009-01-24 09:22:08 2009-01-27 13:10:22 2009-01-27 17:54:15 2009-01-29 08:13:01 2009-01-29 10:28:57 2009-01-29 18:26:59 2009-01-30 12:30:47 2009-01-30 12:31:18 importe 940.00 100.00 64.00 85.00 540.00 50.00 35.00 1420.00 680.00

S E L E C Tc . i d _ c l i e n t e ,C O U N T ( * )n u m _ p e d i d o s ,S U M ( p . i m p o r t e )t o t a lF R O Mc l i e n t e scI N N E RJ O I Np e d i d o s pO Nc . i d _ c l i e n t e=p . i d _ c l i e n t eG R O U PB Yc . i d _ c l i e n t e

id_cliente 2 10

num_pedidos 4 5

total 2545.00 1369.00

Como vemos, el cliente 2 tiene 4 pedidos y el 10 tiene 5. El 13 no aparece porque no tiene ningn pedido y hemos usado INNER JOIN, pero si hubieramos usado LEFT JOIN s aparecera con num_pedidos a 0 (ojo, no NULL, pues es una funcin, no un campo). Tambin hemos sacado, a la vez, la suma de importes de sus pedidos. Si queremos saber cuntos pedidos al da hace un cliente, y de cunto es su pedido con importe ms pequeo, hacemos (MySQL):

S E L E C Tc . i d _ c l i e n t e ,D A T E _ F O R M A T ( p . f e c h a ,' % Y % m % d ' )d i a ,C O U N T ( * )n u m _ p e d i d o s ,M I N ( p . i m p o r t e )A S m i n i m oF R O Mc l i e n t e scI N N E RJ O I Np e d i d o spO Nc . i d _ c l i e n t e=p . i d _ c l i e n t eG R O U PB Yc . i d _ c l i e n t e , d i a

id_cliente 2 2 10 10 2 10

dia 2009-01-24 2009-01-27 2009-01-27 2009-01-29 2009-01-30 2009-01-30

num_pedidos 2 1 1 3 1 1

minimo 100.00 85.00 64.00 35.00 1420.00 680.00

Consultando la BD: optimizar consultas


Sobre la optimizacin hay muchos matices, que dependen siempre del SGBD. Principalmente cada vez que lanzamos una consulta a la BD el SGBD

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

11/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


usa el optimizador para satisfac erla lo ms rpido posible . Si bien es cierto que en oc asiones c onsigue todo lo c ontrario : que se ejecute ms lenta. Como esta informacin es muy especfica para cada SGBD, intentar dar los consejos ms frecuentes para que las consultas vayan mejor, y luego ampliar un poco con MySQL pues es un sistema que se deja optimizar muy bien (aunque sera preferible no tener que optimizarlo...).

Consejos
La primera regla de oro es que el optimizador usar los ndic es para busc ar los registros segn los filtros que le hay amos dado en el W HERE o el ON de las JOINs. As, buscar por un nombre de cliente implicar que no usar ningn ndice si el campo nombre no es ndice. Esto no tiene por qu ser lento, pero relativamente lo ser porque si ese campo fuera un ndice la bsqueda sera mucho ms rpida. Algunos SGBD no tienen penalizaciones por indizar muchos campos de una tabla, pero en MySQL s que la hay ya que el tamao del ndice en general crece haciendo que sea inmensamente mayor y por lo tanto se pierde la ventaja de un ndice ligero. La gestin de los ndices es todo un mundo para los administradores de BD, eso cualquier DBA de Oracle os lo puede decir; as que ante la duda es mejor que consultis Internet o a vuestro admin a ver qu os puede recomendar. El tamao de fila es un valor muy importante en las c onsultas pues, si no hay ndice a usar, se rec orrer toda la fila para busc ar los c ampos del W HERE y as filtrar los resultados. Este valor se puede calcular con los tipos de dato de la tabla, o consultando el esquema INFORMATION_SCHEMA que contiene informacin sobre los meta-datos de todas las BD a las que tenemos acceso. Tambin suele haber herramientas tipo SHOW que pueden devolvernos esa informacin, todo es cuestin de buscar en la documentacin del SGBD. Es importante que los c ampos c lave externa estn indizados pues las JOIN los usan para realizar las uniones de registros con sus relacionados. Si tenemos en cuenta que por cada registro de una tabla primaria en una subordinada puede haber N registros relacionados, ralentizar mucho la consulta no tener un ndice en ese campo referencial. Las subc onsultas son lentas. Esto no es cierto al 100% pero mejor si creemos que s, pues para las subconsultas los SGBD suelen hac er tablas temporales, en memoria o en disco segn pueda o decida qu es lo mejor. No hay que subestimar al optomizador en estos casos pues suele ser muy listo a la hora de dec idir el c amino ms rpido para seguir. ORDER BY y GROUP BY suelen ser enemigos. Ordenar un resultado que se ha agrupado es tarea que los SGBD suelen hacer por ellos mismos, de modo que al agrupar por un campo casi seguro que aprovecha para ordenarlo (ascendementemente) por l. Si intentamos ordenar el resultado por otro campo, MySQL por ejemplo tendr que dar otra vuelta sobre el resultado para re-ordenarlo (apostad porque otros SGBD lo harn tambin). Asmismo, se suelen usar los ndices para el orden del resultado e indicar un orden distinto suele suponer una penalizacin en el tiempo de respuesta. De modo que usad el ORDER BY con la cabeza y cuando sea necesario, porque a vec es ordenamos sin nec esidad . No usis el HAV ING c omo sustituto del W HERE. El HAVING puede servir de WHERE (pero no a la inversa), pero no significa que convenga suplantarlo pues recordad que el filtro HAVING se aplica una vez satisfecho todo lo dems de la consulta: aqu y a no valen las ventajas de los ndic es. Evidentemente si queremos agrupar por un campo y obtener slo los grupos que tengan ms de X elementos o que la suma de uno de sus campos sea menor que Y, no queda otra que usar el HAVING, pues en el tiempo del WHERE no hay manera de saber cunto vale el resultado de una funcin de agregado. El orden de las tablas del JOIN s es importante . Cuando relacionamos tablas en una consulta, ya sea con JOINs o mediante condiciones del WHERE, es cierto que los optimizadores las unirn en el orden que ellos crean conveniente, pero a vec es se equivoc an . Sobre todo MySQL, que parece que cuando usamos JOIN su orden de unin es el que le damos... pero tenemos varias herramientas para solventar este problema: el consejo general es indic ar los JOIN en el orden ms lgic o que se nos oc urra, y si an as el optimizador lo cambia, el SGBD nos suele proporcionar herramientas para indicar en la consulta que se use el ndice que le digamos o se use el orden de unin que explcitamente le indiquemos. Es un buen consejo separar los c ampos c onsultados c on frec uenc ia de los c ampos grandes apenas usados. A veces tenemos en la tabla de clientes un montn de informacin que no se usa casi nunca, pero resulta que esa tabla de clientes es usada con frecuencia. Cuando las consultas no usen un ndice la penalizacin viene dada por el tamao de fila as que tener filas ms pequeas y cortas nos ahorrara muc ho tiempo de respuesta. La solucin es dividir la tabla en dos, con los campos ms frecuenemente consultados en una tabla y los dems en otra (los TEXT, BLOB, y grupos de un muchos campos tipo CHAR/VARCHAR); para esto en la tabla que apenas usaremos nos llevaremos el id de la otra y lo dejaremos c omo c lave primaria y fornea (externa) a su vez, en una relacin 1 a 1 donde la usada con frecuencia sera la fuerte y la otra la subordinada. El tamao de fila del ndic e mejor si es c onstante . Tener campos de tamao variable, como VARCHAR, en un ndice no suele ser buena idea si usas MySQL (sobre todo con el motor MyISAM) por cuestiones de rendimiento e incluso de consistencia. No sera la primera vez en la que yo haya visto que una tabla se corrompe por estas cosas... podemos echarle la culpa al SGBD, al sistema de ficheros del sistema o a lo que sea, pero es mejor que lo tengis en cuenta sobre todo si se rompe con frecuencia una tabla (en mi caso cambiar el engine a InnoDB era posible y solucion el problema). Las transac c iones seguras masivas son ms rpidas que las no seguras. Es habitual que tengamos que hacer cambios masivos en la BD, y especialmente notaremos una buena lentitud cuando sean inserciones. Los SGBD rara vez nos permiten usar distintos motores de almacenamiento de los datos, pero MySQL es un servidor que s nos da a elegir. Es bien sabido que una insercin masiva es ms rpida en MyISAM que en InnoDB, y la razn es la caracterstica de transacciones seguras de InnoDB. MyISAM en contra bloquea las tablas, que es en cierto modo peor si queremos que la tabla siga en uso mientras insertamos, pero la gran demora de InnoDB puede ser un problema... si no usamos transacciones seguras. Un buen truco es iniciar la transaccin segura, START TRANSACTION, realizar los INSERT, y luego finalizar la transaccin segura con COMMIT. Sinceramente no recuerdo si esto es aplicable a otros SGBD como SQL Server u Oracle, pero si os va lento podis probarlo.

Optimizar gracias a EXPLAIN (MySQL)


En MySQL tenis una herramienta muy til para la depuracin de consultas: EXPLAIN. Anteponiendo EXPLIAN a la consulta (EXPLAIN SELECT ... FROM

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

12/13

26/09/13

Artculos: Diseo y uso de bases de datos relacionales. Versin impresin. | PHP-Hispano.net


tabla WHERE ...) obtendremos un detalle de la ejecucin de ella, con datos valiosos como el ndic e que se usa para c ada JOIN, si se realiza un escaneo completo de la tabla, si el sistema tiene que volver a recorrer el resultado para ordenar... es un tema muy amplio para explicarlo en este artculo (adems de que es algo exclusivo de MySQL) as que conviene echarle un ojo a la documentacin oficial para que os hagis una idea de cmo interpretar el resultado de EXPLAIN. Cuando depuris una consulta con EXPLAIN, a grandes rasgos, lo ms importante es fijarse en la columna "type" que determina el tipo de JOIN que realiza el SGBD: "all" significara un esc aneo c ompleto de la tabla, "const" que slo hay un resultado pues se est filtrando por una clave nica comparada con un valor constante, "eq_ref" cuando es una JOIN de tablas relacionadas 1 a N, "ref" cuando la JOIN es de tablas N a M... conviene estudiarlo porque si en una JOIN que une dos tablas el "type" es "all" debemos eperar un resultado lento. Es cierto que en toda consulta con JOINs alguna de las tablas deber ser la primera en leerse y si no se usan filtros de ndice en el WHERE obtendremos un "all", pero quitando ese caso particular en ningn otra JOIN deberamos tener algo que no sea "ref" o "eq_ref". Al fin y al cabo esto es lo que explicbamos ms atras: si no se usan ndices referenciales para satisfacer las JOINs se realiza el producto cartesiano de las tablas con su consecuente consumo de CPU y memoria.

Detectando las consultas lentas


Por lo dems, cuando nuestras aplicaciones vayan muy lentas y detectemos que es por las consultas a la BD, debemos encontrar las consultas que las ralentizan. MySQL tiene el slow_query_log que una vez habilitado en el servidor almacenar todas las consultas que tarden en ejecutarse ms del tiempo que le especifiquemos (un segundo es muy lento, pero medio tambin en una consulta muy frecuente). Una vez que sepamos las consultas podemos revisar los consejos de arriba para ver si estamos haciendo algo mejorable, o quiz tengamos un mal diseo de la BD. Tambin, en ocasiones, nos podemos encontrar que se nos ha olvidado declarar un ndice, y eso tiene una solucin muy fcil. Porque decir que la BD, o una tabla, se nos ha quedado poequea, es algo muy poc o probable : mejor revisar el diseo y el uso que le damos porque dndole una vuelta podemos ver fallos en el diseo y mejorar sobremanera el rendimiento. Si la bsqueda de las consultas lentas se hace muy complicada, siempre podremos buscar algn monitor especfico para nuestro SGBD (en esto el administrador de la BD nos puede ayudar mucho: le conviene) pues estas herramientas suelen proporcionar informacin vital para hallar este tipo de problemas.

Artculo realizado por Eloy Bote Falc n para PHP-Hispano.net Se permite la reproduccin total o parcial del contenido del artculo siempre que se mantenga el autor y una referencia a la fuente original.

php-hispano.net 2002 - 2013 | XHTML 1.0 Datos Legales | W ebmaster

www.php-hispano.net/articulos/modelo-uso-bases-datos-relacionales.html?print=true

13/13

Das könnte Ihnen auch gefallen