El rendimiento de las bases de datos en PHP

¿Qué sistema de acceso a una base de datos es el más rápido en PHP?

En una situación normal, un sitio web con una carga de trabajo baja (pocos usuarios concurrentes), preocuparse por utilizar el sistema más rápido es interesante, pero no esencial. Sin embargo, en un sitio web de éxito, con miles o millones de usuarios, puede ser la clave para el éxito o el hundimiento del sitio web.

En PHP se pueden usar diferentes sistemas de acceso (nativo o a través de una capa intermedia) y en cada uno de ellos existen diferentes posibilidades. Por ejemplo, para MySQL, podemos usar:

  • Acceso nativo: ext/mysql o ext/mysqli (procedural u orientado a objetos).
  • Acceso a través de una capa intermedia: PDO, adoDB, PEAR::DB, un framework.

Un buen banco de pruebas debería tener en cuenta múltiples factores: tipo de consulta (select, insert, update, etc.), tipo de dato (numérico, cadena, etc.), modo de ejecución (sentencia preparada, con o sin buffer, etc.). No hay muchas comparativas y las que he podido encontrar no son concluyentes, ya que algunas incluso muestran resultados contradictorios. Aquí dejo algunas:

A falta de datos concluyentes, mi recomendación es sencilla: usa el método que te parezca más sencillo.

¿PHP o Java?

Hace unos días recibí este correo:

Hola Sergio mi nombre es David te envio un gran saludo desde El Salvador, creeme que tu curso de iDesweb me ayudado muchisimo, actulamente estudio la carrera de ingenieria informatica, sabes estoy a punto de pagar un curso para seguir aprendiendo, ademas necesito trabajar para costearme mis estudios. Bueno he acudido a ti para pedirte asesoria profesional y laboral, decirte que se Java y javascript, pero…que me recomiendas, decidirme por un curso de php o Java EE, fijate que luego de tomar el curso quiero trabajar como te lo dicho antes para poder seguir mis estudios.
Agradecere tu ayuda.
Cuidate.

Y mi respuesta fue:

Es difícil tomar esa decisión, Java o PHP. Por ejemplo, ahora mismo estoy en Ecuador, ayer estuve hablando con un Secretariado del Gobierno. Encontrar programadores de .NET es fácil, pero no encuentran programadores de PHP. Por tanto, depende de muchos factores, puedes estudiar uno de los dos y el día de mañana puedes encontrar un trabajo en el que te pidan usar el otro.

Lo importante es esto: https://blogs.ua.es/pi/2013/12/03/el-lenguaje-que-usaras-todavia-no-se-ha-inventado/

La velocidad de PHP

¿Existen formas mejores o peores de escribir el código en PHP?

Claro, pero todo depende del punto de vista. A veces, el código más rápido de escribir no es el más fácil de entender o el más rápido de ejecutar (eficiente) o el más fácil de mantener. El concepto de “el mejor código” depende de cómo se mida lo de mejor.

Si lo que queremos medir es el tiempo de ejecución, en The PHP Benchmark nos aclaran algunas dudas.

¿Es más rápido echo o print?

¿Es más rápido isset() o empty()?

¿Es más rápido for() o while()?

¿Es más rápido foreach(), for() o while(list() = each())?

¿Es más rápido switch() o if/elseif/else?

Muy, pero que muy interesante.

 

¿Se puede decir que quien escribe esto sabe programar?

Hace tiempo escribí la entrada No está mal, funciona, en la que mostraba la actitud de algunos alumnos a los que sólo les importa que su código funcione, no se molestan en pensar si el código está realmente bien o mal.

Para que lo entienda todo el mundo, es algo parecido a “excrivir un testo con faltas de hortografia”. Se entiende, ¿verdad? Pues está bien, diría alguno de mis alumnos.

Recientemente, mis alumnos (tercer curso) tenían que escribir un código en PHP para permitir el acceso de un usuario a la parte privada de una aplicación web: el típico login con nombre de usuario y contraseña. Más de un alumno (¿un 20%?) escribió lo siguiente o algo parecido:

$sentencia = "SELECT * FROM Usuarios";
$resultado = mysqli_query($link, $sentencia);
while($fila = mysqli_fetch_assoc($resultado)) {
 // $_POST["user"] y $_POST["password"] provienen del formulario de login
 if($fila["User"] == $_POST["user"] && $fila["Password"] == $_POST["password"]) {
   $_SESSION["Id"] = $fila["Id"];
   $_SESSION["Name"] = $fila["Name"];
 }
}
if(!empty($_SESSION["Id"])) {
 // Redirección página principal parte privada
}
else {
 // Redirección página principal parte pública
}

No nos fijemos en que no hay ninguna comprobación de los posibles errores que pueden ocurrir… eso es muy importante, pero no es lo que quiero destacar. ¿Cuál es el problema principal de este código?

Para un ojo educado en la programación, el código anterior es como “ber uvo escrito sin ache y con ube”.

¿Cómo competir con esto?

Recientemente recibí este correo:

Quería aprovechar la ocasión para hacerle una pregunta que me ronda por la cabeza. A partir, de los anteriores videos y usando el framework de Bootstrap realice pruebas diseñando una página Web. Tras esto, y en el punto en el que debía incorporar código para la validación de los usuarios contra la BD, cargar noticias, es decir, darle funcionalidad me surgió la siguiente duda. Existen herramientas como Joomla basadas en templates que automatizan todo el desarrollo de páginas Web añadiendo módulos sobre las plantillas que hacen mucho del trabajo que debemos realizar a la hora de desarrollar una Web, ¿Cómo competir con esto?, Cual es su opinión sobre este tema. (Al final el usuario valora lo que ve no lo que hay detrás)

¿Cómo competir con esto?

Esta es una cuestión que me plantean incluso mis alumnos alguna vez, ¿por qué estudiar HTML, CSS, JavaScript y PHP? ¿Por qué no estudiar un gestor de contenidos como Joomla, Drupal o WordPress? Se pueden hacer webs mejores, en menos tiempo, etc.

En primer lugar, tanto en mis clases en la universidad como en el curso iDESWEB, yo lo que enseño es a desarrollar aplicaciones web. Lo que yo enseño te permitiría crearte tu propio framework, como Codeigniter o Symfony, o incluso tu propio gestor de contenidos como Joomla, Drupal o WordPress. Aunque existan esas herramientas, también tiene que existir alguien que cree y mantenga esas herramientas. Por tanto, aprender a programar con HTML, CSS, JavaScript y PHP es necesario, hace falta gente que sepa.

Un gestor de contenidos no es la panacea, no es la solución para todos los problemas. Desgraciadamente, mucha gente aprende algo y se cree que eso es la solución para todo. El one size fits all pocas veces existe en ingeniería. Sí, existen plugins para los gestores de contenidos que te permiten hacer muchas cosas sin tener que bajar a bajo nivel, sin tener que programar, pero otra vez volvemos a lo mismo: alguien tiene que programar esos plugins. Y muchas veces el plugin no se adapta exactamente a lo que necesitas y tienes que implementar ciertas modificaciones o adaptaciones.

Un gestor de contenidos es muchas veces matar moscas a cañonazos. En la entrada sobre efectividad en la Wikipedia lo explican muy bien:

La efectividad es la capacidad de lograr un efecto deseado, esperado o anhelado. En cambio, eficiencia es la capacidad de lograr el efecto en cuestión con el mínimo de recursos posibles viable.
Ejemplo: matar una mosca de un cañonazo es eficaz (o efectivo: conseguimos el objetivo) pero poco eficiente (se gastan recursos desmesurados para la meta buscada). Pero acabar con su vida con un matamoscas, aparte de ser eficaz es eficiente.

Con los conceptos de eficaz y efectivo llegamos a la madre del cordero: un gestor de contenidos, como Joomla, Drupal o WordPress, consume muchos recursos. ¿Cuántos? Muchos… Una vez encontré una página web en la que se comparaba el tiempo de mostrar un mensaje como “Hello world!” con un HTML estático, con un PHP que ejecuta echo “Hello world!” y con WordPress que tiene una entrada que muestra “Hello world!”. La diferencia de consumo de recursos y de tiempo de ejecución era abismal entre WordPress y las otras dos opciones.

Desgraciadamente, no puedo encontrar esa página otra vez, pero sí que conozco algunas páginas que hacen la misma comparativa pero a nivel de frameworks de PHP (ya hablé de ello en ¿Es lento PHP?):

Por ejemplo, en el último tenemos:

  • Apache static file: 2991.65 Requests/sec with a time per request of 0.334ms.
  • PHP on Apache: 2518.25 requests/sec with a time per request of 0.397.
  • Symfony: 32.21 requests/sec with a time per request of 31.048ms.
  • CakePHP: 34.90 requests/sec with a time per request of 28.657ms.

Solamente utilizar un framework de PHP añade una penalización brutal al tiempo de ejecución. No digamos ya el uso de un gestor de contenidos…

Sí, el tiempo de ejecución de un framework o de un gestor de contenidos se puede mejorar, se puede optimizar, pero en el fondo, siempre existirá una diferencia importante.

Volviendo a la pregunta que se me planteaba, “¿cómo competir con esto?” y “al final el usuario valora lo que ve, no lo que hay detrás”, eso forma parte de los requisitos que se tienen que tener en cuenta a la hora de afrontar un trabajo. ¿El cliente quiere algo exclusivo, único, que sea eficiente, seguro, hecho a medida? Lo veo difícil con un gestor de contenidos.

Esto me recuerda los tres tipos de trabajos que se pueden hacer:

  • Un buen trabajo rápido (no saldrá barato).
  • Un trabajo barato y bueno (no será rápido).
  • Un trabajo barato rápido (no será bueno).

trs-tipos-de-trabajo

Está claro que en el segmento de las webs a 300€ en una semana, plantearse un desarrollo a medida realizado desde cero es un sinsentido. En ese segmento, una web realizada con un gestor de contenidos es una muy buena opción. Pero para alguien que está dispuesto a gastarse varios miles o varios cientos de miles de euros, lo que se pueda hacer con un gestor de contenidos seguramente no le será suficiente.

En realidad, todo esto no es un problema exclusivo del desarrollo web. El mismo problema aparece en otros contextos y se podría encuadrar en problemas que existen en la sociedad actual, como por ejemplo la McDonaldization.

¿Cómo se puede detectar el “user agent” o agente de usuario en PHP?

La cadena  “user agent” o agente de usuario es una cadena que envía un navegador con cada petición HTTP al servidor web.

En PHP se puede acceder a este valor a través del array superglobal $_SERVER. En la documentación oficial se indica que se debe acceder a la posición HTTP_USER_AGENT:

Contenido de la cabecera User-Agent: de la petición actual, si existe. Consiste en una cadena que indica el agente de usuario empleado para acceder a la pagina. Un ejemplo típico es: Mozilla/4.5 [en] (X11; U; Linux 2.2.9 i586). Entre otras opciones, puede emplear dicho valor con get_browser() para personalizar el resultado de la salida de la página en función de las capacidades del agente de usuario empleado.

El siguiente fragmento de código visualiza el valor de la cadena del agente de usuario:

<?php echo $_SERVER['HTTP_USER_AGENT']; ?>

No está mal, funciona

“No está mal, funciona”, es lo que me dicen muchos de mis alumnos cuando les reviso su código y les señalo algunos errores. Sí, funciona, pero eso no es lo único importante. Por ejemplo, veamos el siguiente fragmento de código escrito en PHP:

if(($fichero = @file("testimonios.txt")) == false)
  echo "No se ha podido abrir el fichero";
else
{
  $num = rand(1, count($fichero));
  $i=1;
  foreach($fichero as $numLinea => $linea)
  {
    if ($i==$num)
    {
      list($titulo, $fecha, $contenido) = explode('###', $linea);
      echo "<fieldset><legend><h2>".htmlspecialchars($titulo) ."</h2></legend>";
      echo htmlspecialchars($contenido)."<br /><br />".htmlspecialchars($fecha);
      echo "</fieldset>";
    }
    $i = $i+1;
  }
}

El propósito de este código es leer un fichero (“testimonios.txt”) que tiene el siguiente formato, en el que cada línea es un testimonio de una persona:

titulo###fecha###contenido
titulo###fecha###contenido
titulo###fecha###contenido

Se tiene que elegir una línea al azar y mostrarla.

¿Qué problemas tiene este código?

  1. Utiliza un bucle para localizar en el array el testimonio a mostrar: los arrays son estructuras de acceso directo, si tienes una posición ($num), accedes y punto, no necesitas un bucle para acceder a una posición.
  2. Parece que tampoco entiende el manejo de foreach(): necesita $i para saber en qué posición está, cuando $numLinea ya le valdría.
  3. Cuando por fin encuentra el testimonio y lo muestra ($i==$num), no finaliza el bucle, sigue y sigue buscando en el array hasta llegar al final.
  4. Utiliza el fieldset y el legend, cuyo propósito es agrupar controles en un formulario, para mostrar el testimonio en una “caja bonita” con borde.

Esto no lo ha hecho un alumno de primero, es de un alumno de tercero.