<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Boozox &#187; MySQL</title>
	<atom:link href="http://boozox.net/category/mysql/feed/" rel="self" type="application/rss+xml" />
	<link>http://boozox.net</link>
	<description>Blog de informática, programación, software libre, linux, y mucho más</description>
	<lastBuildDate>Mon, 23 Aug 2010 11:53:12 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>20 Consejos para Mejorar tu MySQL que quizás no conocías</title>
		<link>http://boozox.net/mysql/20-consejos-para-mejorar-tu-mysql-que-quizas-no-conocias/</link>
		<comments>http://boozox.net/mysql/20-consejos-para-mejorar-tu-mysql-que-quizas-no-conocias/#comments</comments>
		<pubDate>Mon, 23 Aug 2010 11:24:06 +0000</pubDate>
		<dc:creator>Alex Barros</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://boozox.net/?p=766</guid>
		<description><![CDATA[Las operaciones sobre bases de datos suelen ser los principales cuellos de botella en las aplicaciones web. Por tanto es tarea de los programadores estructurar apropiadamente, escribir peticiones apropiadas, y programar mejor código. A continuación mostramos algunas técnicas de optimización MySQL.
1. Optimiza tus peticiones para la caché.
La mayoría de servidores MySQL tienen habilitado el sistema [...]]]></description>
			<content:encoded><![CDATA[<p>Las operaciones sobre bases de datos suelen ser los principales cuellos de botella en las aplicaciones web. Por tanto es tarea de los programadores estructurar apropiadamente, escribir peticiones apropiadas, y programar mejor código. A continuación mostramos algunas técnicas de optimización MySQL.</p>
<h2>1. Optimiza tus peticiones para la caché.</h2>
<p>La mayoría de servidores MySQL tienen habilitado el sistema de caché. Es uno de los métodos más efectivos para mejorar el rendimiento, que vienen de la mano del motor de base de datos. Cuando la misma petición se ejecuta varias veces, el resultado se obtiene de la caché, que resulta mucho más rápida.</p>
<p>El problema es que, es tan sencillo y transparente para el programador, que la mayoría de nosotros tendemos a ignorarlo. Algunas cosas que hacemos de hecho pueden evitar que la caché haga su trabajo.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">//La cache NO funciona</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT nombre FROM usuarios WHERE registro &gt;= CURDATE()&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// La caché sí funciona</span></div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$hoy</span> = <a href="http://www.php.net/date"><span class="kw3">date</span></a><span class="br0">&#40;</span><span class="st0">&quot;Y-m-d&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT nombre FROM usuarios WHERE registro &gt;= &#8216;$hoy&#8217;&quot;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>la razón por la que no funciona en el primer caso es por el uso de CURDATE(). Puede aplicarse a todas las funciones no deterministas, como NOW() y RAND(). Dado que el resultado retornado por la función puede cambiar, MySQL decide deshabitar la caché en esa consulta.</p>
<h2>2. Usa EXPLAIN en tus consultas SELECT</h2>
<p>Utilizar la palabra clave <a href="http://dev.mysql.com/doc/refman/5.0/es/explain.html">EXPLAIN</a> te dará muchos detalles internos de lo que hace MySQL para ejecutar tu consulta.  Esto te puede ayudar a detectar los cuellos de botella y otros problemas con tu query o la estructura de la tabla.</p>
<p>El resultado de una query EXPLAIN te mostrará los índices que se están utilizando, cómo se está explorando la tabla, cómo se está ordenando, etc&#8230;</p>
<p>Coge una consulta SELECT (preferiblemente una compleja, con uniones), y añade la palabra EXPLAIN al principio del todo. Puedes utilizar por ejemplo PhpMyAdmin para esto. Te devolverá los resultados en una sencilla tabla. Por ejemplo, pongamos que me he olvidado de poner un índice a una columna, con la que estoy ejecutando</p>
<p><img src="http://boozox.net/wp-content/unoptimized_explain.jpeg" alt="unoptimized_explain" title="unoptimized_explain" width="540" height="242" class="alignnone size-full wp-image-797" /></p>
<p>Después de añadir el índice al campo group_id:</p>
<p><img src="http://boozox.net/wp-content/optimized_explain.jpeg" alt="optimized_explain" title="optimized_explain" width="540" height="280" class="alignnone size-full wp-image-798" /></p>
<p>Ahora en lugar de escanear 7883 filas, sólo escaneará 9 y 16 filas de las dos tablas.</p>
<h2>3. Usa LIMIT 1 Cuando sólo quieras una única fila.</h2>
<p>A veces, cuando estás realizando consultas a tus tablas, ya sabes que sólo necesitas una única fila. En estos casos debes solicitar a la base de datos un único resultado, o de lo contrario comprobará todos y cada uno de las coincidencias de la cláusula WHERE.</p>
<p>En estos casos, añadir LIMIT 1 a tu query puede mejorar significativamente la velocidad. De esta forma la base de datos dejará de escanear resultados en el momento que encuentre uno, en lugar de recorrer toda la tabla o un índice.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">// Tengo usuarios de Valencia?</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// lo que NO hay que hacer:</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT * FROM user WHERE ciudad = &#8216;Valencia&#8217;&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.php.net/mysql_num_rows"><span class="kw3">mysql_num_rows</span></a><span class="br0">&#40;</span><span class="re0">$r</span><span class="br0">&#41;</span> &gt; <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="co1">// &#8230;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// mucho mejor:</span></div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT 1 FROM user WHERE ciudad = &#8216;Valencia&#8217; LIMIT 1&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.php.net/mysql_num_rows"><span class="kw3">mysql_num_rows</span></a><span class="br0">&#40;</span><span class="re0">$r</span><span class="br0">&#41;</span> &gt; <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="co1">// &#8230;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<h2>4. Indexa los campos de Búsqueda</h2>
<p>Los índices no son sólo para las claves primarias o las claves únicas. Si en tu tabla hay columnas sobre las que vas a realizar búsquedas, deberías indexarlas casi siempre.</p>
<p><img src="http://boozox.net/wp-content/search_index.jpg" alt="search_index" title="search_index" width="580" height="225" class="alignnone size-full wp-image-799" /></p>
<p>Como puedes ver, esta regla se aplica también a las búsquedas parciales como &#8220;apellido LIKE &#8216;a%&#8217;&#8221;. Cuando se busca desde el comienzo de la cadena, MySQL es capaz de utilizar el índice de esta columna.</p>
<p>Deberías también comprender en qué tipos de búsqueda no pueden utilizarse índices normales. Por ejemplo, cuando buscas una palabra dentro de un texto (p.e. &#8220;WHERE contenido LIKE &#8216;%manzana%&#8217;&#8221;), no observarás ningún beneficio con un índice normal. En este caso sería mejor utilizar una búsqueda FULLTEXT o construir tu propia solución de indexación.</p>
<h2>5. Indexa, y utiliza el mismo tipo de columna para los Join</h2>
<p>Si tu aplicación contiene muchas sentencias JOIN debes asegurarte de que las columnas que unes están indexadas en ambas tablas. Esto afecta en cómo MySQL optimiza internamente las operaciones JOIN.</p>
<p>Además, las columnas que vas a unir deben ser del mismo tipo. Por ejemplo, si estás uniendo una columna de tipo DECIMAL con una columna de tipo INT de otra tabla, MySQL no será capaz de usar al menos uno de los dos índices. Incluso la codificación de caracteres necesita ser del mismo tipo para las columnas de tipo String.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">// buscando compañias en mi ciudad</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT nombre_companyia FROM usuarios</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; LEFT JOIN companyias ON (usuarios.ciudad = companyias.ciudad)</span></div>
</li>
<li class="li1">
<div class="de1"><span class="st0"> &nbsp; WHERE usuarios.id = $user_id&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// ambas columnas ciudad deben estar indexadas</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// y ambas deberían ser del mismo tipo y codificación de caracteres</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// o MySQL tendrá que hacer un escaneo total de las tablas</span></div>
</li>
</ol>
</div>
<h2>6. No uses ORDER BY RAND()</h2>
<p>Éste es uno de esos truquillos que suenan muy bien a primera vista, y donde muchos programadores novatos suelen caer. Puede que no hayas caído en la cuenta del increíble cuello de botella que se puede provocar si utilizas esta técnica en tus peticiones.</p>
<p>Si en verdad necesitas tablas aleatorias para tu resultado, hay formas mucho mejores de hacerlo. Está claro que ocuparán más código, pero estarás previniendo un posible embotellamiento que aumenta exponencialmente a medida que tu contenido crece. El problema es que MySQL tendrá que ejecutar RAND() (que requiere de potencia de procesado) para cada una de las filas antes de ordenarlas y devolver una simple fila.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">// la forma de NO hacerlo:</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT nombreusuario FROM usuarios ORDER BY RAND() LIMIT 1&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// mucho mejor:</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT count(*) FROM usuarios&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$d</span> = <a href="http://www.php.net/mysql_fetch_row"><span class="kw3">mysql_fetch_row</span></a><span class="br0">&#40;</span><span class="re0">$r</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$rand</span> = <a href="http://www.php.net/mt_rand"><span class="kw3">mt_rand</span></a><span class="br0">&#40;</span><span class="nu0">0</span>,<span class="re0">$d</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> &#8211; <span class="nu0">1</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT nombreusuario FROM usuarios LIMIT $rand, 1&quot;</span><span class="br0">&#41;</span>;</div>
</li>
</ol>
</div>
<p>De forma que seleccionas un número aleatorio inferior a la cantidad de resultados y lo usas como el desplazamiento en la cláusula LIMIT.</p>
<h2>7. Evita SELECT *</h2>
<p>Cuanta más información se lee de las tablas, más lenta se ejecutará la petición SQL. Aumenta el tiempo que toma para las operaciones en disco. Además cuando el servidor de bases de datos está separado del servidor web, tendrás mayores retrasos de red debido a que la información tiene que ser transferida entre ambos servidores.</p>
<p>Es un buen hábito especificar siempre las columnas que necesitas cuando estás haciendo un SELECT.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">// preferible no hacer:</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT * FROM usuarios WHERE id_usuario = 1&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$d</span> = <a href="http://www.php.net/mysql_fetch_assoc"><span class="kw3">mysql_fetch_assoc</span></a><span class="br0">&#40;</span><span class="re0">$r</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;Bienvenido {$d['nombreusuario']}&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// mejor:</span></div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;SELECT nombreusuario FROM usuarios WHERE id_usuario = 1&quot;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="re0">$d</span> = <a href="http://www.php.net/mysql_fetch_assoc"><span class="kw3">mysql_fetch_assoc</span></a><span class="br0">&#40;</span><span class="re0">$r</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><a href="http://www.php.net/echo"><span class="kw3">echo</span></a> <span class="st0">&quot;Bienvenido {$d['nombreusuario']}&quot;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// las diferencias son mucho más significativas cuanta más información haya</span></div>
</li>
</ol>
</div>
<h2>8. Ten casi siempre un campo identificativo</h2>
<p>Ten en cada tabla una columna id con las propiedades PRIMARY KEY, AUTO_INCREMENT y alguna de las variantes de INT. Además es preferible que sea UNSIGNED (sin signo) ya que el valor nunca podrá ser negativo.</p>
<p>Incluso si tienes una tabla de usuarios cuyos nombres de usuario sean únicos, no los uses como clave primaria. Los campos VARCHAR como clave primaria son muy lentos. Y tendrás una mejor estructura en tu código si referencias a todos tus usuarios por sus ids internamente.</p>
<p>También hay una serie de operaciones internas que realiza el motor de MySQL por sí mismo, que usa la clave primaria, lo cual se hace incluso más importante cuanto más compleja sea la base de datos (clusters, particionados, etc&#8230;).</p>
<p>Una posible excepción a la regla son las &#8220;tablas de asociación&#8221;, utilizadas en las relaciones &#8220;muchos a muchos&#8221; entre dos tablas. Por ejemplo, una tabla &#8220;etiquetas_articulos&#8221; que contiene dos columnas: id_articulo, id_etiqueta, que es utilizada para las relaciones entre las tablas &#8220;articulos&#8221; y &#8220;etiquetas&#8221;. Estas tablas pueden tener una clave PRIMARY que contenga ambos campos.</p>
<h2>9. Usa ENUM antes que VARCHAR</h2>
<p>Las columnas de tipo ENUM son muy rápidas y compactas. Internamente se almacenan como TINYINT, aunque pueden contener y representar valores de cadenas. Esto las hace un perfecto candidato para algunos campos.</p>
<p>Si tienes un campo que contendrá sólo unos pocos valores distintos, utiliza ENUM en lugar de VARCHAR. Por ejemplo, podría ser una columna llamada &#8220;estado&#8221;, y sólo unos pocos valores como &#8220;activo&#8221;, &#8220;inactivo&#8221;, &#8220;pendiente&#8221;, &#8220;caducado&#8221;, etc&#8230;</p>
<p>De hecho hay una forma de obtener sugerencias del propio MySQL para reestructurar nuestra tabla. Cuando tienes un campo VARCHAR te puede sugerir que cambies ésa columna al tipo ENUM. Esto se hace utilizando la llamada a PROCEDURE ANALYSE(). Lo cual nos lleva a:</p>
<h2>10. Obtén sugerencias con PROCEDURE ANALYSE()</h2>
<p>PROCEDURE ANALYSE() permitirá a MySQL analizar la estructura de las columnas y los datos actuales que contienen para retornar ciertas sugerencias que serán de tu interés. Sólo es útil si hay información en las tablas, porque esto toma gran importancia en la toma de decisiones.</p>
<p>Por ejemplo, si creaste un campo INT para tu clave primaria, pero no tienes muchas filas, podría sugerirte que uses MEDIUMINT en su lugar. O si estas usando un campo VARCHAR, podría sugerirte que lo conviertas en ENUM, si sólo estás escribiendo unos pocos valores.</p>
<p>También puedes ejecutarlo pulsando en &#8220;Propose table structure&#8221; (proponer estructura de tabla) en la interfaz de PhpMyAdmin, en una de las vistas de tus tablas.</p>
<p><img src="http://boozox.net/wp-content/suggestions.jpeg" alt="suggestions" title="suggestions" width="418" height="249" class="alignnone size-full wp-image-800" /></p>
<p>Ten presente que esto son sólo sugerencias. Y si tu tabla va a crecer mucho, podrían no ser buenas sugerencias a seguir. La decisión es tuya en última instancia.</p>
<h2>11. Usa NOT NULL si puedes</h2>
<p>A no ser que tengas una razón específica para usar el valor NULL, deberías establecer siempre tus columnas como NOT NULL.</p>
<p>En primer lugar, pregúntate a tí mismo si habría alguna diferencia entre tener una cadena vacía y un valor NULL (o para campos INT: 0 contra NULL). Si no hay problema entre los dos valores, no necesitas un campo NULL. (¿Sabías que Oracle considera a NULL y una cadena vacía como lo mismo?)</p>
<p>Las columnas NULL necesitan espacio adicional y pueden añadir complejidad a tus sentencias de comparación. Simplemente evítalas siempre que puedas. En cualquier caso, entiendo que en algunos casos muy específicos haya razón para usar columnas NULL, lo cual no es siempre algo malo.</p>
<p>Extraído de la documentación de MySQL:</p>
<blockquote><p>“las columnas NULL requieren espacio adicional en la fila a grabar donde los valores son NULL. Para las tablas MyISAM, cada columna NULL toma un bit extra, redondeando hacia arriba al byte más cercano.”</p></blockquote>
<h2>12. Declaraciones preparadas</h2>
<p>Existen múltiples beneficios al usar declaraciones preparadas, tanto a nivel de productividad como de seguridad.</p>
<p>Las declaraciones preparadas filtran las variables que le pasas por defecto, lo que es perfecto para proteger tu aplicación contra ataques de inyección SQL. Claro que puedes filtrar tus variables manualmente, pero estos métodos son propensos al error humano y al despiste del programador. Este problema no es tan acentuado cuando se utiliza algún tipo de Framework u ORM.</p>
<p>Ya que queríamos centrarnos en la productividad, deberíamos mencionar los beneficios que ofrece este area. Estos beneficios son más significativos cuando la misma consulta va a utilizarse varias veces en tu aplicación. Puedes asignar diferentes valores a una misma declaración, y MySQL sólo tendrá que analizarla una vez.</p>
<p>Además, las últimas versiones de MySQL transmiten declaraciones preparadas de forma binaria nativamente, más eficientes y que ayudan a reducir los retrasos de red.</p>
<p>Hubo un tiempo en que muchos programadores solían evitar las declaraciones preparadas a propósito, por una única razón: no estaban siendo cacheadas por la caché de consultas de MySQL. Pero aproximadamente en la versión 5.1, el cacheo de consultas también ha sido soportado.</p>
<p>Para utilizar declaraciones preparadas en PHP puedes echar un ojo a la extensión mysqli o utilizar una capa de abstracción de base de datos como PDO.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="co1">// creamos la declaración preparada</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$stmt</span> = <span class="re0">$mysqli</span>-&gt;<span class="me1">prepare</span><span class="br0">&#40;</span><span class="st0">&quot;SELECT nombre FROM usuarios WHERE ciudad=?&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="co1">// pasamos los parámetros</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp;<span class="re0">$stmt</span>-&gt;<span class="me1">bind_param</span><span class="br0">&#40;</span><span class="st0">&quot;s&quot;</span>, <span class="re0">$ciudad</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="co1">// ejecutamos</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="re0">$stmt</span>-&gt;<span class="me1">execute</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp;<span class="co1">// pasamos la variable de resultado</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="re0">$stmt</span>-&gt;<span class="me1">bind_result</span><span class="br0">&#40;</span><span class="re0">$nombre</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="co1">// obtenemos el resultado</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="re0">$stmt</span>-&gt;<span class="me1">fetch</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<a href="http://www.php.net/printf"><span class="kw3">printf</span></a><span class="br0">&#40;</span><span class="st0">&quot;%s es de %s<span class="es0">\n</span>&quot;</span>, <span class="re0">$nombre</span>, <span class="re0">$ciudad</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp;<span class="re0">$stmt</span>-&gt;<span class="me1">close</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
</ol>
</div>
<h2>13. Consultas fuera de buffer</h2>
<p>Normalmente cuando estás ejecutando una consulta en un script, éste se esperará a que acabe la ejecución de esta consulta antes de que pueda continuar. Pero puedes cambiar este comportamiento sacando la consulta fuera del búffer.</p>
<p>Puedes echar un ojo a la genial explicación que hacen en la documentación de PHP para la función the mysql_unbuffered_query():</p>
<blockquote><p>“mysql_unbuffered_query() envía la query SQL a MySQL, sin recuperar ni colocar en búfer las filas de resultado automáticamente, como mysql_query() lo hace. Por una parte, esto ahorra una considerable cantidad de memoria con las consultas SQL que producen conjuntos grandes de resultados y se puede empezar a trabajar con el conjunto de resultado inmediatamente después de que la primera fila ha sido recuperada: no necesita esperar hasta que la consulta SQL completa haya sido ejecutada. Para usar mysql_unbuffered_query() cuando se usan múltiples conexiones con la BD, se necesita indicar el parámetro opcional link_identifier para identificar que conexión se desea utilizar.”</p></blockquote>
<p>Sin embargo los beneficios de mysql_unbuffered_query() tienen un precio: no poder usar mysql_num_rows() ni mysql_data_seek() en un conjunto de resultados devuelto por mysql_unbuffered_query(). También tendrás que recuperar todas las filas de resultado de una consulta SQL sin búfer antes de poder enviar una nueva consulta SQL a MySQL.</p>
<h2>14. Almacena las direcciones IP como UNSIGNED INT</h2>
<p>Muchos programadores crearían un campo VARCHAR(15) sin darse cuenta de que pueden almacenar las direcciones IP como números enteros. Cuando usas un INT sólo haces uso de 4 bytes en la memoria, y cuenta además con un tamaño fijo en la tabla.</p>
<p>Pero hay que asegurarse de que la columna sea UNSIGNED INT (entero sin signo) porque las direcciones IP hacen uso de todo el rango de 32 bits sin signo.</p>
<p> En tus consultas puedes utilizar la función INET_ATON() para convertir una dirección IP en entero, e INET_NTOA() para hacer lo contrario. También existen funciones parecidas en PHP llamadas ip2long() y long2ip().</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="re0">$r</span> = <span class="st0">&quot;UPDATE users SET ip = INET_ATON(&#8217;{$_SERVER['REMOTE_ADDR']}&#8217;) WHERE user_id = $user_id&quot;</span>;</div>
</li>
</ol>
</div>
<h2>15. Las tablas de tamaño fijo (Estáticas) son más rápidas</h2>
<p>Cuando cada una de las columnas en una tabla es de tamaña fijo (&#8221;fixed-length&#8221;), la tabla entera se considera <a href="http://dev.mysql.com/doc/refman/5.1/en/static-format.html">&#8220;estática&#8221; o de &#8220;tamaño fijo&#8221;</a>. Algunos ejemplos de tipos de columna que NO son de tamaño fijo son:  VARCHAR, TEXT, BLOB. Si incluyes sólo uno de estos tipos de columna, la tabla dejará de ser de tamaño fijo y tendrá que ser tratada de forma distinta por el motor de MySQL.</p>
<p>Las tablas de tamaño fijo pueden incrementar la productividad porque para el motor de MySQL es más rápido buscar entre sus registros. Cuando quiere leer una fila en concreto de la tabla, puede calcular rápidamente la posición que ocupa. Si el tamaño de fila no es fijo, cada vez que tiene que buscar, ha de consultar primero el índice de la clave primaria.</p>
<p>También resultan más sencillas de cachear, y de reconstruir después de un accidente. Pero por otra parte también podrían ocupar más espacio. Por ejemplo, si conviertes un campo VARCHAR(20) en CHAR(20), siempre ocupará 20 bytes en la memoria independientemente de lo que contenga.</p>
<p>Usando técnicas de &#8220;Particionado Vertical&#8221;, puedes separar las columnas de tamaño variable en una tabla aparte. Lo cual nos lleva a:</p>
<h2>16. Particionado Vertical</h2>
<p>El particionado vertical es el acto de separar la estructura de tu tabla de forma vertical por razones de optimización.</p>
<p><strong>Ejemplo 1:</strong> Seguramente tendrás una tabla de usuarios que contiene una dirección postal, la cual no se utiliza muy a menudo. Aquí podrías dividir la tabla y almacenar las direcciones en una tabla separada. De esta forma tu tabla de usuarios principal tendría un tamaño más ajustado. Como sabes, cuanto más pequeñas más rápidas son las tablas.</p>
<p><strong>Ejemplo 2:</strong> Tienes un campo de &#8220;ultimo_acceso&#8221; en tu tabla. Se actualiza cada vez que un  usuario accede a tu página. Pero cada acceso hace que la cache de consultas de esa tabla se libere. Lo que puedes hacer es colocar este campo en otra tabla para que las modificaciones en tu tabla de usuarios se mantenga al mínimo.</p>
<p>Pero también tienes que asegurarte de que no necesitas juntar las dos tablas constantemente después del particionado o sufrirás una caída en el rendimiento, justo lo contrario a lo que buscábamos.</p>
<h2>17. Divide las consultas DELETE o INSERT grandes</h2>
<p>Si necesitas ejecutar una consulta DELETE o INSERT que sea grande en una página web activa, tienes que tener cuidado de no alterar el tráfico web. Cuando una consulta grande como esas se ejecuta, puede bloquear tus tablas y paralizar tu aplicación web momentaneamente.</p>
<p>Apache ejecuta muchos procesos/hilos paralelamente. De ahí que funcione mucho más eficientemente cuando los scripts dejan de ejecutarse tan pronto como es posible, para que los servidores no experimenten muchas conexiones abiertas y procesos de una que consumen recursos, especialmente memoria primaria.</p>
<p>Si en algún momento bloqueas tus tablas en un periodo largo (como 30 segundos o más), en una web con mucho tráfico, causarás un apilamiento de procesos y consultas, que llevará mucho tiempo de concluir o que incluso podría estropear tu servidor web.</p>
<p>Si tienes algún script de mantenimiento que tiene que borrar una gran cantidad de filas, simplemente utiliza la cláusula LIMIT para hacerlo en porciones más pequeñas y así evitar la congestión.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">while</span> <span class="br0">&#40;</span><span class="nu0">1</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> &nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <a href="http://www.php.net/mysql_query"><span class="kw3">mysql_query</span></a><span class="br0">&#40;</span><span class="st0">&quot;DELETE FROM logs WHERE log_date &lt;= &#8216;2009-10-01&#8242; LIMIT 10000&quot;</span><span class="br0">&#41;</span>; &nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><a href="http://www.php.net/mysql_affected_rows"><span class="kw3">mysql_affected_rows</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span> == <span class="nu0">0</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> &nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// finalizado el borrado</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span>; &nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="co1">// incluso viene bien parar un poco</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <a href="http://www.php.net/usleep"><span class="kw3">usleep</span></a><span class="br0">&#40;</span><span class="nu0">50000</span><span class="br0">&#41;</span>; &nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span> &nbsp;</div>
</li>
</ol>
</div>
<h2>18. Las columnas pequeñas son más rápidas</h2>
<p>En los motores de bases de datos, la memoria en disco probablemente sea el cuello de botella más significativo. En términos de productividad, mantener las cosas reducidas y más compactas suele ayudar a reducir la cantidad de transferencia desde disco.</p>
<p>La documentación de MySQL tiene una lista de <a href="http://dev.mysql.com/doc/refman/5.0/es/storage-requirements.html">Requerimientos de Almacenamiento</a> para todos los tipos de dato.</p>
<p>Si está previsto que una tabla tenga muy pocos registros, no hay razón para usar un INT para la clave primaria, en lugar de un MEDIUMINT, SMALLINT o incluso en algunos casos TINYINT. Y si no necesitas el componente del tiempo, puedes utilizar DATE en lugar de DATETIME.</p>
<p>Simplemente, debes asegurarte de que dejas espacio razonable para poder crecer, o podrías acabar como Slashdot.</p>
<h2>19. Escoge el motor de almacenamiento adecuado</h2>
<p>Los dos principales motores en MySQL son MyISAM y InnoDB, Cada uno tiene sus pros y sus contras.</p>
<p>MyISAM is adecuado para aplicaciones con mucha lectura, pero no escala cuando hay muchas escrituras. Incluso si estás editando un campo de una fila, la tabla completa se bloquea, y ningún otro proceso puede siquiera leer hasta que la consulta ha finalizado. MyISAM es muy rápido calculando consultas de tipo SELECT COUNT(*).</p>
<p>Inno DB tiende a ser un motor más complicado y puede ser más lento que MyISAM para la mayoría de aplicaciones pequeñas. Pero soporta bloqueo basado en fila, lo cual escala mejor. También soporta algunas características más avanzadas como las transacciones. </p>
<ul>
<li><a href="http://dev.mysql.com/doc/refman/5.0/es/myisam-storage-engine.html">Motor MyISAM</a></li>
<li><a href="http://dev.mysql.com/doc/refman/5.1/en/innodb.html">Motor InnoDB</a></li>
</ul>
<h2>20. Usa un Mapeador de objetos relacionales</h2>
<p>Al usar un ORM (Object Relational Mapper), puedes conseguir algunas mejoras en la productividad. Cualquier cosa que puede hacer un ORM, puedes programarlo a mano también. Pero podría significar demasiado trabajo extra y requerir de un alto nivel de experiencia.</p>
<p>Los ORM son perfectos para la &#8220;carga perezosa&#8221;. Significa que se puede obtener valores sólo cuando se necesitan. Pero hay que tener cuidado porque podría acabar creando demasiadas mini peticiones que perjudicarían al rendimiento.</p>
<p>Los ORM también pueden agrupar tus consultas en transacciones, que operan mucho más rápido que enviar consultas individuales a la base de datos.</p>
<p>Actualmente un ORM recomendable para PHP es <a href="http://www.doctrine-project.org/">Doctrine</a>. Puedes leer cómo instalarlo <a href="http://www.phpandstuff.com/articles/codeigniter-doctrine-from-scratch-day-1-install-and-setup">en este artículo</a> (<em>inglés</em>).</p>
<h2>21. Ten cuidado con las conexiones persistentes</h2>
<p>El objetivo de las Conexiones Persistentes es reducir el esfuerzo de reabrir conexiones con MySQL. Cuando se crea una conexión persistente, queda abierta incluso después de que el script haya acabado de ejecutarse. Dado que Apache reutiliza sus procesos hijos, el siguiente script reutilizaría la misma conexión MySQL. </p>
<ul>
<li><a href="http://php.net/manual/es/function.mysql-pconnect.php">mysql_pconnect en PHP</a></li>
</ul>
<p>En la teoría suena muy bien. Pero desde mi experiencia personal (y la de muchos otros), esta característica acaba por no merecer la pena. Puedes tener serios problemas con los límites de conexión, problemas de memoria y mucho más.</p>
<p>Apache ejecuta de forma extremadamente paralela, y crea muchos procesos hijo. Esta es la principal razón por la que las conexiones persistentes no funcionan muy bien en este entorno. Antes de que consideres usar la función mysql_pconnect(), consulta a tu administrador de sistemas.</p>
<p><strong>Extraído y traducido de <a href="http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/">nettuts</a> por Alex Barros. Fecha del original: 25-11-09.</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://boozox.net/mysql/20-consejos-para-mejorar-tu-mysql-que-quizas-no-conocias/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>5 máximas</title>
		<link>http://boozox.net/mysql/5-maximas/</link>
		<comments>http://boozox.net/mysql/5-maximas/#comments</comments>
		<pubDate>Mon, 28 Sep 2009 23:51:04 +0000</pubDate>
		<dc:creator>Alex Barros</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://boozox.net/?p=717</guid>
		<description><![CDATA[Hoy se me han pasado por la cabeza estas máximas que creo que mueven mi vida.

Ser Feliz
Echarle Morro
Reclamar lo que es justo
Currárselo mucho
Hacer que todo merezca la pena

No necesariamente en ese orden, sinó todas a la vez.
Ah, y por teneros un poco up-to-date: Actualmente retomando Informática (esta vez de Gestión), rodando y mejorando la WebSerie [...]]]></description>
			<content:encoded><![CDATA[<p>Hoy se me han pasado por la cabeza estas máximas que creo que mueven mi vida.</p>
<ol style="font-size: 2em">
<li>Ser Feliz</li>
<li>Echarle Morro</li>
<li>Reclamar lo que es justo</li>
<li>Currárselo mucho</li>
<li>Hacer que todo merezca la pena</li>
</ol>
<p>No necesariamente en ese orden, sinó todas a la vez.</p>
<p>Ah, y por teneros un poco up-to-date: Actualmente retomando Informática (esta vez de Gestión), rodando y mejorando la WebSerie Tu Muerte Está Cerca, Trabajos diversos como himformático, y trabajos diversos como colaborador en rodajes.</p>
]]></content:encoded>
			<wfw:commentRss>http://boozox.net/mysql/5-maximas/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Curiosidad en la sintaxis del SELECT</title>
		<link>http://boozox.net/mysql/curiosidad-en-la-sintaxis-del-select/</link>
		<comments>http://boozox.net/mysql/curiosidad-en-la-sintaxis-del-select/#comments</comments>
		<pubDate>Mon, 27 Oct 2008 04:17:23 +0000</pubDate>
		<dc:creator>Alex Barros</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://boozox.net/?p=580</guid>
		<description><![CDATA[Hace poco descubrí una curiosidad de SQL símplemente revisando la documentación del SELECT. Por eso creo que es interesante repasar la sintaxis oficial, para que no se nos escape nada.



SELECT


&#160; &#160; &#91;ALL &#124; DISTINCT &#124; DISTINCTROW &#93;


&#160; &#160; &#160; &#91;HIGH_PRIORITY&#93;


&#160; &#160; &#160; &#91;STRAIGHT_JOIN&#93;


&#160; &#160; &#160; &#91;SQL_SMALL_RESULT&#93; &#91;SQL_BIG_RESULT&#93; &#91;SQL_BUFFER_RESULT&#93;


&#160; &#160; &#160; &#91;SQL_CACHE &#124; SQL_NO_CACHE&#93; &#91;SQL_CALC_FOUND_ROWS&#93;


&#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>Hace poco descubrí una <strong>curiosidad de SQL</strong> símplemente revisando la <a href="http://dev.mysql.com/doc/refman/5.0/en/select.html">documentación del SELECT</a>. Por eso creo que es interesante repasar la sintaxis oficial, para que no se nos escape nada.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">ALL</span> | <span class="kw1">DISTINCT</span> | DISTINCTROW <span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span>HIGH_PRIORITY<span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">STRAIGHT_JOIN</span><span class="br0">&#93;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span>SQL_SMALL_RESULT<span class="br0">&#93;</span> <span class="br0">&#91;</span>SQL_BIG_RESULT<span class="br0">&#93;</span> <span class="br0">&#91;</span>SQL_BUFFER_RESULT<span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span>SQL_CACHE | SQL_NO_CACHE<span class="br0">&#93;</span> <span class="br0">&#91;</span>SQL_CALC_FOUND_ROWS<span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; select_expr, &#8230;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">FROM</span> table_references</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">WHERE</span> where_condition<span class="br0">&#93;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">GROUP</span> <span class="kw1">BY</span> <span class="br0">&#123;</span>col_name | expr | position<span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">ASC</span> | <span class="kw1">DESC</span><span class="br0">&#93;</span>, &#8230; <span class="br0">&#91;</span><span class="kw1">WITH</span> ROLLUP<span class="br0">&#93;</span><span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">HAVING</span> where_condition<span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">ORDER</span> <span class="kw1">BY</span> <span class="br0">&#123;</span>col_name | expr | position<span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">ASC</span> | <span class="kw1">DESC</span><span class="br0">&#93;</span>, &#8230;<span class="br0">&#93;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">LIMIT</span> <span class="br0">&#123;</span><span class="br0">&#91;</span>offset,<span class="br0">&#93;</span> row_count | row_count OFFSET offset<span class="br0">&#125;</span><span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#91;</span>PROCEDURE procedure_name<span class="br0">&#40;</span>argument_list<span class="br0">&#41;</span><span class="br0">&#93;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">INTO</span> <span class="kw1">OUTFILE</span> <span class="st0">&#8216;file_name&#8217;</span> export_options</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; | <span class="kw1">INTO</span> DUMPFILE <span class="st0">&#8216;file_name&#8217;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; | <span class="kw1">INTO</span> var_name <span class="br0">&#91;</span>, var_name<span class="br0">&#93;</span><span class="br0">&#93;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#91;</span><span class="kw1">FOR</span> <span class="kw1">UPDATE</span> | <span class="kw1">LOCK</span> <span class="kw1">IN</span> SHARE MODE<span class="br0">&#93;</span><span class="br0">&#93;</span></div>
</li>
</ol>
</div>
<h2>La curiosidad</h2>
<p>Lo que yo desconocía es que es posible ordenar los resultados por <strong>dos campos o más</strong>. Es decir, hacer la ordenación en función de varios parámetros.</p>
<p><strong>Un ejemplo:</strong></p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> a,b,c <span class="kw1">FROM</span> mi_tabla <span class="kw1">WHERE</span> a &gt; <span class="nu0">100</span> <span class="kw1">ORDER</span> <span class="kw1">BY</span> b,c</div>
</li>
</ol>
</div>
<p>En este Select, los resultados son ordenados según b y c de la mejor forma posible. Puede que ni b ni c queden ordenados estrictamente, sinó que <strong>adoptan las mejores posiciones para estar ordenados por ambos a la vez</strong>.</p>
<p>Yendo más lejos aún, podemos especificar campo a campo si queremos que se ordene <strong>ascendentemente o descendientemente</strong>, combinando varios criterios.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> a,b,c <span class="kw1">FROM</span> mi_tabla <span class="kw1">WHERE</span> a &gt; <span class="nu0">100</span> <span class="kw1">ORDER</span> <span class="kw1">BY</span> b <span class="kw1">ASC</span>,c <span class="kw1">DESC</span></div>
</li>
</ol>
</div>
]]></content:encoded>
			<wfw:commentRss>http://boozox.net/mysql/curiosidad-en-la-sintaxis-del-select/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>MySQL &#8211; Seleccionar al azar, o lista desordenada</title>
		<link>http://boozox.net/mysql/mysql-seleccionar-al-azar-o-una-lista-desordenada/</link>
		<comments>http://boozox.net/mysql/mysql-seleccionar-al-azar-o-una-lista-desordenada/#comments</comments>
		<pubDate>Sun, 10 Aug 2008 23:15:17 +0000</pubDate>
		<dc:creator>Alex Barros</dc:creator>
				<category><![CDATA[Código]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://boozox.net/?p=380</guid>
		<description><![CDATA[Tan sencillo como usar la función RAND() de MySQL.
La clave está en ordenar los elementos seleccionados por un parámetro aleatorio. Un ejemplo sería esta sentencia:



SELECT * FROM mi_tabla WHERE a &#62; 10 AND b &#60; 200 ORDER BY RAND&#40;&#41;



Esto nos daría los resultados que queremos, ordenados aleatoriamente.
Si queremos coger un sólo registro al azar, no [...]]]></description>
			<content:encoded><![CDATA[<p>Tan sencillo como usar la función <strong><a href="http://mysql.conclase.net/curso/index.php?fun=RAND">RAND()</a></strong> de MySQL.</p>
<p>La clave está en <strong>ordenar los elementos</strong> seleccionados por un parámetro <strong>aleatorio</strong>. Un ejemplo sería esta sentencia:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> mi_tabla <span class="kw1">WHERE</span> a &gt; <span class="nu0">10</span> <span class="kw1">AND</span> b &lt; <span class="nu0">200</span> <span class="kw1">ORDER</span> <span class="kw1">BY</span> RAND<span class="br0">&#40;</span><span class="br0">&#41;</span></div>
</li>
</ol>
</div>
<p>Esto nos daría los resultados que queremos, ordenados <strong>aleatoriamente</strong>.</p>
<p>Si queremos coger <strong>un sólo registro al azar</strong>, no tenemos más que limitar el anterior Select a un registro.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> mi_tabla <span class="kw1">WHERE</span> a &gt; <span class="nu0">10</span> <span class="kw1">AND</span> b &lt; <span class="nu0">200</span> <span class="kw1">ORDER</span> <span class="kw1">BY</span> RAND<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">LIMIT</span> <span class="nu0">1</span></div>
</li>
</ol>
</div>
<p>Como diría <a href="http://tentacul.us/track/2294/">Janet Jackson</a>, I want FeedBack!!</p>
]]></content:encoded>
			<wfw:commentRss>http://boozox.net/mysql/mysql-seleccionar-al-azar-o-una-lista-desordenada/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Explicación visual de los SQL Join &#8211; Unir tablas con SQL</title>
		<link>http://boozox.net/mysql/explicacion-visual-de-los-sql-join-unir-tablas-con-sql/</link>
		<comments>http://boozox.net/mysql/explicacion-visual-de-los-sql-join-unir-tablas-con-sql/#comments</comments>
		<pubDate>Fri, 12 Oct 2007 21:10:03 +0000</pubDate>
		<dc:creator>Alex Barros</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://boozox.net/mysql/explicacion-visual-de-los-sql-join-unir-tablas-con-sql/</guid>
		<description><![CDATA[Me ha parecido muy interesante el artículo escrito por Jeff Atwood titulado A Visual Explanation of SQL Joins.
Tanto es así que he decidido traducir este artículo al español. Disfrutad:
Autor Original: Jeff Atwood
Fecha: 11/10/07
Traductor: Alex Barros
Pensé que el post de Ligaya Turmelle sobre SQL joins era una genial introducción para los desarrolladores primerizos. Dado que los [...]]]></description>
			<content:encoded><![CDATA[<p>Me ha parecido muy interesante el artículo escrito por <a href="http://www.codinghorror.com/blog/">Jeff Atwood</a> titulado <a href="http://www.codinghorror.com/blog/archives/000976.html">A Visual Explanation of SQL Joins</a>.</p>
<p>Tanto es así que he decidido traducir este artículo al español. Disfrutad:</p>
<p><strong>Autor Original:</strong> Jeff Atwood<br />
<strong>Fecha:</strong> 11/10/07<br />
<strong>Traductor:</strong> Alex Barros</p>
<p>Pensé que el post de Ligaya Turmelle <a href="http://www.khankennels.com/blog/index.php/archives/2007/04/20/getting-joins">sobre SQL joins</a> era una genial introducción para los desarrolladores primerizos. Dado que los SQL joins están basados fundamentalmente en conjuntos relacionados, el uso de diagramas de Venn para explicarlo parece lo más acertado. De todas formas, igual que los comentaristas de su post, opino que sus diagramas de Venn no encajaban con la <a href="http://es.wikipedia.org/wiki/JOIN">sintaxis de SQL join</a> en mis pruebas.</p>
<p>Aún así me encanta el concepto, así que veamos si podemos hacerlo funcionar. Supongamos que tenemos las dos siguientes tablas. La tabla A está a la izquierda, y la tabla B está a la derecha. Las rellenaremos con cuatro registros cada una.</p>
<p><img src='http://boozox.net/wp-content/tabla-sqljoin.png' alt='tabla A y B muestra' /></p>
<p>Ahora unamos estas dos tablas por el campo nombre de algunas formas distintas, y veamos si podemos obtener unas representaciones conceptuales con los ingeniosos diagramas de Venn.</p>
<p><strong>Inner join</strong> sólo produce los registros que coinciden en las dos tablas A y B.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> TablaA</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">INNER</span> <span class="kw1">JOIN</span> TablaB</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">ON</span> TablaA.nombre = TablaB.nombre</div>
</li>
</ol>
</div>
<p><img src='http://boozox.net/wp-content/tabla_sqljoin-1.png' alt='Resultado de Inner Join' /> <img src='http://boozox.net/wp-content/join-inner.png' alt='Join Inner'/></p>
<p><strong>Full outer join</strong> produce el conjunto de todos los registros en las tablas A y B, con registros coincidentes en ambos lados cuando sea posible. Si no hay coincidencia, el lado que falta contendrá <em>null</em>.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> TablaA</div>
</li>
<li class="li1">
<div class="de1">FULL <span class="kw1">OUTER</span> <span class="kw1">JOIN</span> TablaB</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">ON</span> TablaA.nombre = TablaB.nombre</div>
</li>
</ol>
</div>
<p><img src='http://boozox.net/wp-content/tabla_sqljoin-2.png' alt='Resultado de Full Outer Join' /> <img src='http://boozox.net/wp-content/join-cartesian.png' alt='Join Cartesian' /></p>
<p><strong>Left outer join</strong> produce el conjunto completo de registros de la tabla A, con los registros coincidentes (si están disponibles) en la tabla B. Si no hay coincidencia, el lado derecho contendrá null.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> TablaA</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">LEFT</span> <span class="kw1">OUTER</span> <span class="kw1">JOIN</span> TablaB</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">ON</span> TablaA.nombre = TablaB.nombre</div>
</li>
</ol>
</div>
<p><img src='http://boozox.net/wp-content/tabla_sqljoin-3.png' alt='Resultado de Left Outer Join' /> <img src='http://boozox.net/wp-content/join-left.png' alt='Join Left' /></p>
<p>Para producir el conjunto de registros en la tabla A, pero no en la tabla B, usamos el mismo Left Outer Join, y luego <strong>excluimos los registros que no queremos del lado derecho mediante una cláusula Where</strong>.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> TablaA</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">LEFT</span> <span class="kw1">OUTER</span> <span class="kw1">JOIN</span> TablaB</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">ON</span> TablaA.nombre = TablaB.nombre</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">WHERE</span> TablaB.id <span class="kw1">IS</span> <span class="kw1">NULL</span></div>
</li>
</ol>
</div>
<p><img src='http://boozox.net/wp-content/tabla_sqljoin-4.png' alt='Resultado de Left Outer Join con exclusión' /> <img src='http://boozox.net/wp-content/join-left-outer.png' alt='Join Left Outer' /></p>
<p>Para producir el conjunto de registros únicos de la tabla A y la tabla B, usamos el mismo Full Outer Join, y luego <strong>excluimos los registros que no queremos de los dos lados mediante una cláusula Where</strong>.</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> TablaA</div>
</li>
<li class="li1">
<div class="de1">FULL <span class="kw1">OUTER</span> <span class="kw1">JOIN</span> TablaB</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">ON</span> TablaA.nombre = TablaB.nombre</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">WHERE</span> TablaA.id <span class="kw1">IS</span> <span class="kw1">NULL</span> </div>
</li>
<li class="li2">
<div class="de2"><span class="kw1">OR</span> TablaB.id <span class="kw1">IS</span> <span class="kw1">NULL</span></div>
</li>
</ol>
</div>
<p><img src='http://boozox.net/wp-content/tabla_sqljoin-5.png' alt='Resultado de Full Outer Join con exclusión' /> <img src='http://boozox.net/wp-content/join-outer.png' alt='Join Outer' /></p>
<p>También hay un <strong>cross join</strong>, el cuál no puede ser expresado con un diagrama de Venn:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> TablaA</div>
</li>
<li class="li1">
<div class="de1"><span class="kw1">CROSS</span> <span class="kw1">JOIN</span> TablaB</div>
</li>
</ol>
</div>
<p>Esto une &#8220;todo con todo&#8221;, dando como resultado 4 x 4 = 16 filas, muchas más de las que teníamos en los conjuntos originales. Si haces unos simples cálculos, puedes ver por qué es un Join muy peligroso de ejecutar en tablas grandes.</p>
<p><strong>Ver también: <a href="http://boozox.net/boozox/multiples-join-y-solucion-al-encadenar-left-joins/">Hacer Múltiples Join en una sola Sentencia</a></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://boozox.net/mysql/explicacion-visual-de-los-sql-join-unir-tablas-con-sql/feed/</wfw:commentRss>
		<slash:comments>120</slash:comments>
		</item>
		<item>
		<title>INNER JOIN para unir Tablas</title>
		<link>http://boozox.net/mysql/inner-join-para-unir-tablas/</link>
		<comments>http://boozox.net/mysql/inner-join-para-unir-tablas/#comments</comments>
		<pubDate>Tue, 14 Mar 2006 23:24:04 +0000</pubDate>
		<dc:creator>Alex Barros</dc:creator>
				<category><![CDATA[Código]]></category>
		<category><![CDATA[HOWTO/CóMO]]></category>
		<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://boozox.net/boozox/inner-join-para-unir-tablas/</guid>
		<description><![CDATA[Ver también: Explicación visual de los SQL Join
Ver también: Hacer Múltiples Join en una sola Sentencia
Muy bien, aprendices del Sql, hoy hablaremos de la instrucción INNER JOIN. Muy útil para casos concretos.
Primero de todo vamos a crear una situación hipotética:
Imaginemos que tenemos que hacer una web que contiene unos artículos en referencia a comentarios de [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Ver también: <a href="http://boozox.net/mysql/explicacion-visual-de-los-sql-join-unir-tablas-con-sql/">Explicación visual de los SQL Join</a></strong><br />
<strong>Ver también: <a href="http://boozox.net/boozox/multiples-join-y-solucion-al-encadenar-left-joins/">Hacer Múltiples Join en una sola Sentencia</a></strong></p>
<p>Muy bien, aprendices del Sql, hoy hablaremos de la instrucción <strong>INNER JOIN</strong>. Muy útil para casos concretos.</p>
<p>Primero de todo vamos a crear una situación hipotética:</p>
<p>Imaginemos que tenemos que hacer una web que contiene unos artículos en referencia a comentarios de novelas, y que son doce escritores de prestigio los que van introduciendo esas críticas.</p>
<p>Lo normal y más básico para un programador sería pensar en base de datos y lenguaje dinámico. Una buena elección podría ser trabajar con PHP y MySql (aunque para lo que voy a decir basta con una base de datos de tipo Sql).</p>
<p>Lo primero que nos viene a la mente es: haré una tabla, llamémosla <em><strong>criticas</strong></em>. En ella almacenaríamos cada artículo. Los campos básicos serían <u>ID</u>, <u>Libro</u>, Escritor <em>(del libro, nunca confundir con el autor de la crítica)</em>, Editorial, año &#8230; y <strong>Autor de la crítica</strong>.</p>
<p>Pero y si quisiéramos, como es normal, poner en la misma crítica una referencia al <strong>autor de la critica</strong>, aúnque sólo sea un pequeño texto biográfico? Tendríamos que repetir un mismo texto repetidas veces en la base (la biografia de doce autores en, pongamos 150 registros) y si quisieramos modificarlo y hubiera 70 entradas con ese autor&#8230; eso sería un desastre.</p>
<p><img src="http://modulos.zumbe.net/imagenes/inner_join_criticas.gif" alt="http://modulos.zumbe.net/imagenes/inner_join_criticas.gif" /></p>
<p>Entonces queda claro que hay que hacer una referencia a otra tabla que contenga a los autores, con sus respectivos datos. La tabla <em><strong>autores</strong></em>. Cada autor tendría su ID, su nombre y su biografía, además de otros datos como webpage, e-mail, bibliografía&#8230;</p>
<p>Algunos dirían: pues fácil, haces dos querys a la base. en uno le dices</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> criticas <span class="kw1">WHERE</span> ID =<span class="st0">&#8216;37&#8242;</span></div>
</li>
</ol>
</div>
<p>y en otra</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> autores <span class="kw1">WHERE</span> &#8230;</div>
</li>
</ol>
</div>
<p>where qué? tendrías que sacar una variable de sql a php, otra vez a sql&#8230;<br />
Nada! Si alguien sugiere eso desconfiad de él y de su familia (es broma ;D) existe un método sencillo y eficaz: el <u><strong>INNER JOIN</strong></u></p>
<p>Tan sencilla es la sentencia como:</p>
<div class="dean_ch" style="white-space: wrap;">
<ol>
<li class="li1">
<div class="de1"><span class="kw1">SELECT</span> * <span class="kw1">FROM</span> criticas <span class="kw1">INNER</span> <span class="kw1">JOIN</span> autores <span class="kw1">ON</span> criticas.autor = autores.id <span class="kw1">WHERE</span> criticas.id=<span class="st0">&#8216;7&#8242;</span></div>
</li>
</ol>
</div>
<p>De esta forma estamos uniendo las dos tablas, cada vez que en criticas el autor sea n, en autores se unirá su correspondiente fila, con id=n.</p>
<p>Traduciendo al español la sentencia dice exactamente:</p>
<p>SELECCIONA TODOS LOS CAMPOS UNIENDO criticas CON autores DONDE el campo autor de la tabla criticas SEA IGUAL A el campo id de la tabla autores EN EL REGISTRO EN QUE el id de criticas sea 7</p>
<p>En definitiva, el inner join une dos tablas, donde encajan un campo de una con el mismo de la otra.</p>
<p>A partir de ahora las tablas se hacen más manejables y flexibles.</p>
<p><strong><span style="color: darkred">Y recordad!</span></strong>:</p>
<ul>
<li>Para seleccionar campos de cada tabla : <em>tabla.campo</em> universal en sql, dato importante.</li>
<li>Estructura del inner join: SELECT campos FROM tabla1 INNER JOIN tabla2 ON tabla1.campo = tabla2.campo</li>
<li>Antes de hacer barbaridades con vuestras bases de datos documentaos un poco, lo digo por experiencia <img src='http://boozox.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://boozox.net/mysql/inner-join-para-unir-tablas/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
	</channel>
</rss>
