Mise en cache des requêtes
Il y a 4 façons de mettre en cache une requête.
-
Utiliser une astuce SQL pour chaque requête
-
L'utilisation fourni une fonction de rappel pour prise de décision pour chaque requête,
par exemple, en utilisant la fonction mysqlnd_qc_is_select()
-
Utilisation de la fonction mysqlnd_set_cache_condition()
pour des règles automatiques pour chaque requête
-
Utilisation de la directive
mysqlnd_qc.cache_by_default = 1
pour mettre en cache toutes les requêtes aveuglément
L'utilisation d'astuce SQL et de la directive de configuration
mysqlnd_qc.cache_by_default = 1
sont expliquées ci-dessous. Reportez-vous à la documentation sur la fonction
mysqlnd_qc_is_select() pour une description de l'utilisation d'une
fonction de rappel et à la documentation sur la fonction
mysqlnd_qc_set_cache_condition() sur la façon pour
définir des règles automatiques pour la mise en cache.
Une astuce SQL est un commentaire standard SQL. Comme tout commentaire SQL, il sera
ignoré par la base de données. Une requête est considérée éligible à la mise en cache
si elle commence par une astuce SQL activant la mise en cache, ou si c'est une
requête de type SELECT
.
Une requête individuelle qui doit être mise en cache doit commencer avec l'astuce SQL
/*qc=on*/
. Il est recommandé d'utiliser la constante PHP
MYSQLND_QC_ENABLE_SWITCH
au lieu d'utiliser la chaîne ci-dessus.
-
non éligible pour la mise en cache, et non mise en cache : INSERT INTO test(id) VALUES (1)
-
non éligible à la mise en cache et non mise en cache : SHOW ENGINES
-
éligible à la mise en cache, mais non mise en cache : SELECT id FROM test
-
éligible à la mise en cache et mise en cache : /*qc=on*/SELECT id FROM test
L'exemple avec la chaîne de requête SELECT
est préfixé
avec l'astuce SQL MYSQLND_QC_ENABLE_SWITCH
pour active la mise en cache de la requête. L'astuce SQL doit être fournie
au tout début de la chaîne de requête pour activer la mise en cache.
Exemple #1 Utilisation de l'astuce SQL MYSQLND_QC_ENABLE_SWITCH
<?php
/* Connexion, création et peuplement de la table test */
$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");
/* Sera mis en cache en raison de la présence de l'astuce SQL */
$start = microtime(true);
$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();
printf("Durée de la requête non mise en cache : %.6fs\n", microtime(true) - $start);
/* Récupération depuis le cache */
$start = microtime(true);
$res = $mysqli->query("/*" . MYSQLND_QC_ENABLE_SWITCH . "*/" . "SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();
printf("Durée de la requête mise en cache : %.6fs\n", microtime(true) - $start);
?>
Les exemples ci-dessus vont afficher :
array(1) {
["id"]=>
string(1) "1"
}
Durée de la requête non mise en cache : 0.000740s
array(1) {
["id"]=>
string(1) "1"
}
Durée de la requête mise en cache : 0.000098s
Si rien de plus n'est configuré, comme c'est le cas dans l'exemple de démarrage rapide,
le plugin utilisera le gestionnaire de stockage interne default
.
Le gestionnaire de stockage default
utilise un processus
mémoire pour stocker une entrée du cache. Suivant le modèle de déployement PHP,
un processus PHP peut servir une ou plusieurs requêtes web. Veuillez consulter
le manuel de votre serveur web pour plus de détails. Ces détails ne feront
aucune différence dans les exemples de cette section.
Le plugin de mise en cache de requêtes va mettre en cache toutes les requêtes
si la chaîne commence par une astuce SQL qui active ou non la mise en cache,
si la directive de configuration PHP
mysqlnd_qc.cache_by_default
vaut 1
. La configuration
mysqlnd_qc.cache_by_default
est évaluée par le coeur du plugin de mise en cache de requêtes. Aussi,
ni le coeur du plugin, ni un gestionnaire de stockage défini par l'utilisateur ne
peuvent écraser cette configuration.
L'astuce SQL /*qc=off*/
peut être utilisée pour désactiver
la mise en cache d'une requête si
mysqlnd_qc.cache_by_default = 1
.
Il est recommandé d'utiliser la constante PHP
MYSQLND_QC_DISABLE_SWITCH
au lieu de la valeur litérale.
Exemple #2 Utilisation de l'astuce SQL MYSQLND_QC_DISABLE_SWITCH
mysqlnd_qc.enable_qc=1
mysqlnd_qc.cache_by_default=1
<?php
/* Connexion, création et peuplement de la table test */
$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");
/* Sera mise en cache malgré le fait qu'aucune astuce SQL ne soit présente,
car 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");
/* Récupération depuis le cache - aucune invalidation automatique, et donc, toujours valide ! */
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();
/* Non présente dans le cache - la requête ne doit pas être mise en cache en raison de
la présence de l'astuce SQL */
$res = $mysqli->query("/*" . MYSQLND_QC_DISABLE_SWITCH . "*/SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();
?>
Les exemples ci-dessus vont afficher :
array(1) {
["id"]=>
string(1) "1"
}
array(1) {
["id"]=>
string(1) "1"
}
NULL
PECL/mysqlnd_qc ne mettra pas en cache les requêtes pour lesquelles au moins
une colonne du jeu de résultats ne contient pas le nom de la table dans ses
méta-données par défaut. C'est habituellement le cas pour les colonnes
provenant de fonctions SQL comme
NOW()
ou LAST_INSERT_ID()
. La politique
vise à éviter les pièges, si la mise en cache est utilisée par défaut.
Exemple #3 Exemple montrant les types de requêtes non mis en cache
mysqlnd_qc.enable_qc=1
mysqlnd_qc.cache_by_default=1
<?php
/* Connexion, création et peuplement de la table test */
$mysqli = new mysqli("host", "user", "password", "schema", "port", "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++) {
$start = microtime(true);
/* Note : la requête ne sera pas mise en cache car NOW() est utilisé */
$res = $mysqli->query("SELECT id, NOW() AS _time FROM test");
$row = $res->fetch_assoc();
/* Affichage des résultats */
var_dump($row);
printf("Durée d'exécution : %.6fs\n", microtime(true) - $start);
/* On attend une seconde */
sleep(1);
}
?>
Les exemples ci-dessus vont afficher :
array(2) {
["id"]=>
string(1) "1"
["_time"]=>
string(19) "2012-01-11 15:43:10"
}
Durée d'exécution : 0.000540s
array(2) {
["id"]=>
string(1) "1"
["_time"]=>
string(19) "2012-01-11 15:43:11"
}
Durée d'exécution : 0.000555s
array(2) {
["id"]=>
string(1) "1"
["_time"]=>
string(19) "2012-01-11 15:43:12"
}
Durée d'exécution : 0.000549s
Il est possible d'activer la mise en cache pour toutes les requêtes,
y compris celles qui contiennent des colonnes dans leur jeu de résultats
pour lesquelles MySQL rapporte aucune table, comme la requête de l'exemple
ci-dessus. Définissez la directive de configuration comme ceci
mysqlnd_qc.cache_no_table = 1
pour activer la mise en cache de telle requête. Notez la différence dans les
durées mesurées de l'exemple ci-dessus et de l'exemple ci-dessous.
Exemple #4 Activation du cache pour toutes les requêtes
en utilisant l'option de configuration ini
mysqlnd_qc.cache_no_table
mysqlnd_qc.enable_qc=1
mysqlnd_qc.cache_by_default=1
mysqlnd_qc.cache_no_table=1
<?php
/* Connexion, création et peuplement de la table test */
$mysqli = new mysqli("host", "user", "password", "schema", "port", "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++) {
$start = microtime(true);
/* Note : la requête ne sera pas mise en cache car NOW() est utilisé */
$res = $mysqli->query("SELECT id, NOW() AS _time FROM test");
$row = $res->fetch_assoc();
/* Affichage des résultats */
var_dump($row);
printf("Durée d'exécution : %.6fs\n", microtime(true) - $start);
/* On attend une seconde */
sleep(1);
}
?>
Les exemples ci-dessus vont afficher :
array(2) {
["id"]=>
string(1) "1"
["_time"]=>
string(19) "2012-01-11 15:47:45"
}
Total time: 0.000546s
array(2) {
["id"]=>
string(1) "1"
["_time"]=>
string(19) "2012-01-11 15:47:45"
}
Durée d'exécution : 0.000187s
array(2) {
["id"]=>
string(1) "1"
["_time"]=>
string(19) "2012-01-11 15:47:45"
}
Durée d'exécution : 0.000167s
Note:
Bien que mysqlnd_qc.cache_no_table = 1
a été créé pour une utilisation avec
mysqlnd_qc.cache_by_default = 1
,
il y est lié. Le plugin va évaluer la directive
mysqlnd_qc.cache_no_table
à chaque fois qu'une requête est prête à être mise en cache, sans tenir compte de
l'activation du cache en utilisant une astuce SQL ou toute autre mesure.