The PHP Online Conference 2021

Almacenar consultas en la caché

Hay cuatro maneras de desencadenar el almacenamiento en caché de una consulta.

  • Usar sugerencias SQL en función de cada consulta
  • Llamadas de retorno porporcionadas por el usuario para decidir en función de cada consulta, por ejemplo, usando mysqlnd_qc_is_select()
  • mysqlnd_set_cache_condition() para reglas basadas en decisiones automáticas en cada consulta
  • mysqlnd_qc.cache_by_default = 1 para almacenar en caché todas las consultas a ciegas

El uso de las sugerencias SQL y de mysqlnd_qc.cache_by_default = 1 se expilca más abajo. Por vafor, consulte la referenca de la función mysqlnd_qc_is_select() para una descripción del uso de una llamada de retorno, y de mysqlnd_qc_set_cache_condition() sobre cómo establecer reglas para el almacenamiento automático en caché.

Una sugerencia SQL es un comentario que sigue los estándares. Como comentario de SQL, es ignorado por la base de datos. Una consulta es considerada candidata para su almacenamiento en caché si comienza con la sugerencia SQL que habilita dicho almacenamiento o si es una sentencia SELECT.

Una consulta individual que debiera ser almacenada debe comenzar con la sugerencia SQL /*qc=on*/. Se recomienda usar la constante de PHP MYSQLND_QC_ENABLE_SWITCH en lugar del valor de cadena.

  • no candidata para su almacenamiento en caché y no almacenada: INSERT INTO test(id) VALUES (1)

  • no candidata para su almacenamiento en caché y no almacenada: SHOW ENGINES

  • candidata para su almacenamiento en caché pero no almacenada: SELECT id FROM test

  • candidata para su almacenamiento y almacenada: /*qc=on*/SELECT id FROM test

Las sentencias SELECT del ejemplo están prefijadas con la sugerencia SQL MYSQLND_QC_ENABLE_SWITCH para habilitar su almacenamiento en caché. La sugerencia SQL debe colocarse al comienzo de la cadena de consulta para habilitar el almacenamiento en caché.

Ejemplo #1 Usar la sugerencia SQL MYSQLND_QC_ENABLE_SWITCH

mysqlnd_qc.enable_qc=1
<?php
/* Conectar, crear y rellenar la tabla test */
$mysqli = new mysqli("host""usuario""contraseña""esquema""puerto""socket");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");

/* Será almacenada en caché debido a la sugerencia SQL */
$inicio microtime(true);
$res   $mysqli->query("/*" MYSQLND_QC_ENABLE_SWITCH "*/" "SELECT id FROM test WHERE id = 1");

var_dump($res->fetch_assoc());
$res->free();

printf("Tiempo total de consulta no almacenada: %.6fs\n"microtime(true) - $inicio);

/* Coincidencia con la caché */
$inicio microtime(true);
$res   $mysqli->query("/*" MYSQLND_QC_ENABLE_SWITCH "*/" "SELECT id FROM test WHERE id = 1");

var_dump($res->fetch_assoc());
$res->free();

printf("Tiempo total de consulta almacenada: %.6fs\n"microtime(true) - $inicio);
?>

El resultado de los ejemplos sería algo similar a:

array(1) {
  ["id"]=>
  string(1) "1"
}
Tiempo total de consulta no almacenada: 0.000740s
array(1) {
  ["id"]=>
  string(1) "1"
}
Tiempo total de consulta almacenada: 0.000098s

Si no se configura nada más, como es el caso del ejemplo de esta guía rápida, el complemento usará en gestor de almacenamiento interno default. El gestor de almacenamiento default utiliza la memoria del proceso para mantener una entrada de la caché. Dependiendo del modelo de desarrollo de PHP, un proceso de PHP podría servir una o más peticiones web. Por favor, consulte el manual del servidor web para más detalles. Los detalles son irrelevantes para los ejemplos dados en esta guía rápida.

El complemento de caché de consultas almacenará todas las consultas sin considerar si la cadena de consulta comienza con la sugerencia SQL que habilita dicho almacenamiento, si la directiva de configuración de PHP mysqlnd_qc.cache_by_default está establecida a 1. El ajuste mysqlnd_qc.cache_by_default es evaluado por el núcleo del complemento de caché de consultas. Ni el gestor de almacenamiento interno ni uno definido por el usuario pueden sobrescribir el ajuste.

La sugerencia SQL /*qc=off*/ se puede usar para deshabilitar el almacenamiento en caché de consultas individuales si mysqlnd_qc.cache_by_default = 1. Se recomienda usar la constante de PHP MYSQLND_QC_DISABLE_SWITCH en lugar del valor de cadena.

Ejemplo #2 Usar la sugerencia SQL MYSQLND_QC_DISABLE_SWITCH

mysqlnd_qc.enable_qc=1
mysqlnd_qc.cache_by_default=1
<?php
/* Conectar, crear y rellenar la tabla test */
$mysqli = new mysqli("host""usuario""contraseña""esquema""puerto""socket");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");

/* Será almacenada aunque no esté presente ninguna sugerencia SQL ya que mysqlnd_qc.cache_by_default = 1*/
$res $mysqli->query("SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();

$mysqli->query("DELETE FROM test WHERE id = 1");

/* Coincidencia con la caché - ¡sin invalidación automática y aún válida! */
$res $mysqli->query("SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();

/* No coincide con la caché - la consulta no debe almacenarse debido a la sugerencia SQL */
$res $mysqli->query("/*" MYSQLND_QC_DISABLE_SWITCH "*/SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();
?>

El resultado de los ejemplos sería:

array(1) {
  ["id"]=>
  string(1) "1"
}
array(1) {
  ["id"]=>
  string(1) "1"
}
NULL

PECL/mysqlnd_qc prohíbe el almacenamiento en la caché de sentencias donde al menos una columna del conjunto de resultados de dichas sentencias no muestren el nombre de la tabla en sus metadatos de forma predeterminada. Éste normalmente es el caso para las columnas originadas desde funciones SQL tales como NOW() o LAST_INSERT_ID(). La política se dirige a prevenir fallos si se usa el almacenamiento por omisión.

Ejemplo #3 Ejemplo que muestra qué tipos de sentencias no son almacenadas en la caché

mysqlnd_qc.enable_qc=1
mysqlnd_qc.cache_by_default=1
<?php
/* Conectar, crear y rellenar la tabla test */
$mysqli = new mysqli("host""usuario""contraseña""esquema""puerto""socket");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1)");

for (
$i 0$i 3$i++) {

    
$inicio microtime(true);

    
/* Nota: la sentencia no será almacenada debido al uso de NOW() */
    
$res $mysqli->query("SELECT id, NOW() AS _time FROM test");
    
$fila $res->fetch_assoc();

    
/* volcar resultados */
    
var_dump($fila);

    
printf("Tiempo total: %.6fs\n"microtime(true) - $inicio);

    
/* pausar durante un segundo */
    
sleep(1);
}
?>

El resultado de los ejemplos sería algo similar a:

array(2) {
  ["id"]=>
  string(1) "1"
  ["_time"]=>
  string(19) "2012-01-11 15:43:10"
}
Tiempo total: 0.000540s
array(2) {
  ["id"]=>
  string(1) "1"
  ["_time"]=>
  string(19) "2012-01-11 15:43:11"
}
Tiempo total: 0.000555s
array(2) {
  ["id"]=>
  string(1) "1"
  ["_time"]=>
  string(19) "2012-01-11 15:43:12"
}
Tiempo total: 0.000549s

Es posible habilitar el almacenamiento en caché para todas las sentecias incluyendo aquellas que tienen columnas en su conjunto de resultados para las cuales MySQL no notifica una tabla, como la sentencia del ejemplo. Se ha de establecer mysqlnd_qc.cache_no_table = 1 para habilitar el almacenamiento en caché de tales sentencias. Por favor, observe la diferencia en los tiempos medidos para los ejemplos de arriba y de abajo.

Ejemplo #4 Habilitar el almacenamiento en caché de todas las sentencias usando el ajuste ini mysqlnd_qc.cache_no_table

mysqlnd_qc.enable_qc=1
mysqlnd_qc.cache_by_default=1
mysqlnd_qc.cache_no_table=1
<?php
/* Conectar, crear y rellenar la tabla test */
$mysqli = new mysqli("host""usuario""contraseña""esquema""puerto""socket");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1)");

for (
$i 0$i 3$i++) {

    
$inicio microtime(true);

    
/* Nota: la sentencia no será almacenada debido al uso de NOW() */
    
$res $mysqli->query("SELECT id, NOW() AS _time FROM test");
    
$fila $res->fetch_assoc();

    
/* volcar resultados */
    
var_dump($fila);

    
printf("Tiempo total: %.6fs\n"microtime(true) - $inicio);

    
/* pausar durante un segundo */
    
sleep(1);
}
?>

El resultado de los ejemplos sería algo similar a:

array(2) {
  ["id"]=>
  string(1) "1"
  ["_time"]=>
  string(19) "2012-01-11 15:47:45"
}
Tiempo total: 0.000546s
array(2) {
  ["id"]=>
  string(1) "1"
  ["_time"]=>
  string(19) "2012-01-11 15:47:45"
}
Tiempo total: 0.000187s
array(2) {
  ["id"]=>
  string(1) "1"
  ["_time"]=>
  string(19) "2012-01-11 15:47:45"
}
Tiempo total: 0.000167s

Nota:

Aunque mysqlnd_qc.cache_no_table = 1 haya sido creado para usarlo con mysqlnd_qc.cache_by_default = 1 está vilculado a él. El complemento evaluará mysqlnd_qc.cache_no_table siempre que se vaya a almacenar una consulta, sin importar si el almacenameinto en caché ha sido habilitado usando una sugerencia SQL o cualquier otra medida.

add a note add a note

User Contributed Notes 1 note

up
2
laurent at pele dot org
3 years ago
This query cache feature enhances a lot performance of my web site, unfortunately, installation dll are available on windows only up to version 5.5. For example, if I use it on php 5.6, there is an error message on startup saying it is not compatible
To Top