SELECT une seule fois, puis de servir les exécutions suivantes de la même requête directement depuis le cache.
Selon le type de requêtes, cela peut réduire considérablement la latence et la consommation de ressources du serveur ClickHouse.
Contexte, conception et limites
- Dans les caches transactionnellement cohérents, la base de données invalide (écarte) les résultats de requête mis en cache si le résultat de la requête
SELECTchange ou est susceptible de changer. Dans ClickHouse, les opérations qui modifient les données incluent les insertions/mises à jour/suppressions dans les tables ou les merges avec collapsing. La mise en cache transactionnellement cohérente est particulièrement adaptée aux bases de données OLTP, par exemple MySQL (qui a supprimé le cache de requêtes après la version 8.0) et Oracle. - Dans les caches transactionnellement incohérents, de légères imprécisions dans les résultats de requête sont acceptées, en partant du principe que toutes les entrées de cache se voient
attribuer une période de validité après laquelle elles expirent (par ex. 1 minute) et que les données sous-jacentes évoluent peu pendant cette période.
Cette approche est globalement plus adaptée aux bases de données OLAP. Comme exemple où une mise en cache transactionnellement incohérente est suffisante,
prenons un rapport de ventes horaire dans un outil de reporting consulté simultanément par plusieurs utilisateurs. Les données de ventes changent généralement
assez lentement pour que la base de données n’ait besoin de calculer le rapport qu’une seule fois (ce que représente la première requête
SELECT). Les requêtes suivantes peuvent ensuite être renvoyées directement depuis le cache de requêtes. Dans cet exemple, une période de validité raisonnable pourrait être de 30 min.
Paramètres de configuration et utilisation
Dans ClickHouse Cloud, vous devez utiliser les paramètres au niveau de la requête pour modifier les paramètres du cache de requêtes. La modification des paramètres au niveau de la configuration n’est actuellement pas prise en charge.
clickhouse-local n’exécute qu’une seule requête à la fois. Comme la mise en cache des résultats de requête n’a pas de sens dans ce cas, le cache des résultats de requête
est désactivé dans clickhouse-local.
use_query_cache = true) liront
le résultat calculé depuis le cache et le renverront immédiatement.
Le paramètre
use_query_cache et tous les autres paramètres liés au cache de requêtes ne prennent effet que pour des instructions SELECT autonomes. En particulier,
les résultats des SELECT sur des vues créées par CREATE VIEW AS SELECT [...] SETTINGS use_query_cache = true ne sont pas mis en cache, sauf si l’instruction SELECT
est exécutée avec SETTINGS use_query_cache = true.true par défaut). Le premier paramètre
contrôle si les résultats des requêtes sont stockés dans le cache, tandis que le second détermine si la base de données doit tenter de récupérer les résultats des requêtes
depuis le cache. Par exemple, la requête suivante n’utilisera le cache que passivement, c’est-à-dire qu’elle tentera d’y lire sans y stocker son
résultat :
use_query_cache, enable_writes_to_query_cache et
enable_reads_from_query_cache qu’avec des requêtes spécifiques. Il est également possible d’activer la mise en cache au niveau de l’utilisateur ou du profil (par ex. via SET use_query_cache = true), mais il faut garder à l’esprit que toutes les requêtes SELECT peuvent alors renvoyer des résultats en cache.
Le cache de requêtes peut être vidé à l’aide de l’instruction SYSTEM CLEAR QUERY CACHE. Le contenu du cache de requêtes est affiché dans la table système
system.query_cache. Le nombre de succès et d’échecs du cache de requêtes depuis le démarrage de la base de données est affiché sous forme d’événements
“QueryCacheHits” et “QueryCacheMisses” dans la table système system.events. Ces deux compteurs ne sont mis à jour que pour les
requêtes SELECT exécutées avec le paramètre use_query_cache = true ; les autres requêtes n’affectent pas “QueryCacheMisses”. Le champ query_cache_usage
dans la table système system.query_log indique, pour chaque requête exécutée, si le résultat de la requête a été écrit dans le cache de requêtes ou
lu depuis celui-ci. Les métriques QueryCacheEntries et QueryCacheBytes dans la table système
system.metrics indiquent combien d’entrées / d’octets le cache de requêtes contient actuellement.
Le cache de requêtes existe en un seul exemplaire par processus serveur ClickHouse. Cependant, les résultats en cache ne sont, par défaut, pas partagés entre les utilisateurs. Cela peut être
modifié (voir ci-dessous), mais ce n’est pas recommandé pour des raisons de sécurité.
Les résultats de requête sont référencés dans le cache de requêtes par l’Abstract Syntax Tree (AST) de
la requête. Cela signifie que la mise en cache est insensible à la casse ; par exemple, SELECT 1 et select 1 sont traités comme une seule et même requête. Pour
rendre la correspondance plus naturelle, tous les paramètres au niveau de la requête liés au cache de requêtes et au formatage de sortie)
sont supprimés de l’AST.
Si la requête a été interrompue en raison d’une exception ou annulée par l’utilisateur, aucune entrée n’est écrite dans le cache de requêtes.
La taille du cache de requêtes en octets, le nombre maximal d’entrées de cache et la taille maximale des entrées individuelles (en octets et en
enregistrements) peuvent être configurés à l’aide de différentes options de configuration du serveur.
users.xml, puis rendez les deux paramètres
readonly:
Age et Expires avec l’âge (en secondes) et l’horodatage d’expiration de l’entrée
mise en cache.
Les entrées du cache de requêtes sont compressées par défaut. Cela réduit la consommation globale de mémoire au prix d’écritures plus lentes dans / de lectures plus lentes
depuis le cache de requêtes. Pour désactiver la compression, utilisez le paramètre query_cache_compress_entries.
Il est parfois utile de conserver en cache plusieurs résultats pour la même requête. Cela peut être réalisé à l’aide du paramètre
query_cache_tag, qui agit comme une étiquette (ou un espace de noms) pour les entrées du cache de requêtes. Le cache de requêtes
considère comme différents les résultats de la même requête avec des tags différents.
Exemple de création de trois entrées différentes dans le cache de requêtes pour la même requête :
tag du cache de requêtes, vous pouvez utiliser l’instruction SYSTEM CLEAR QUERY CACHE TAG 'tag'.
Mise en cache des sous-requêtes
use_query_cache dans la requête externe n’est pas appliqué aux sous-requêtes. Cela signifie que chaque sous-requête doit activer explicitement la mise en cache :
query_cache_for_subqueries :
use_query_cache = false pour cette sous-requête :
is_subquery = 1. Le paramètre query_cache_ttl s’applique également aux entrées du cache de sous-requête et peut être défini pour chaque sous-requête.
ClickHouse lit les données des tables en blocs de max_block_size lignes. En raison du filtrage, de l’agrégation,
etc., les blocs de résultat sont généralement bien plus petits que ‘max_block_size’, mais dans certains cas, ils peuvent aussi être bien plus grands. Le paramètre
query_cache_squash_partial_results (activé par défaut) détermine si les blocs de résultat
sont fusionnés (s’ils sont très petits) ou divisés (s’ils sont volumineux) en blocs de taille ‘max_block_size’ avant leur insertion dans le cache de résultat de la requête.
Cela réduit les performances d’écriture dans le cache de requêtes, mais améliore le taux de compression des entrées du cache et offre une
granularité de blocs plus naturelle lorsque les résultats des requêtes sont ensuite servis depuis le cache de requêtes.
Par conséquent, le cache de requêtes stocke pour chaque requête plusieurs
blocs de résultat partiels. Bien que ce comportement constitue un bon choix par défaut, il peut être désactivé à l’aide du paramètre
query_cache_squash_partial_results.
De plus, les résultats des requêtes contenant des fonctions non déterministes ne sont pas mis en cache par défaut. Ces fonctions incluent
- les fonctions d’accès aux Dictionaries :
dictGet(), etc. - les User-Defined Functions sans la balise
<deterministic>true</deterministic>dans leur définition XML, - les fonctions qui renvoient la date ou l’heure actuelles :
now(),today(),yesterday(), etc., - les fonctions dont le résultat dépend de la taille et de l’ordre des chunks internes utilisés pour le traitement des requêtes :
nowInBlock(), etc.,rowNumberInBlock(),runningDifference(),blockSize(), etc., - les fonctions qui renvoient des valeurs aléatoires :
randomString(),fuzzBits(), etc., - les fonctions qui dépendent de l’environnement :
currentUser(),queryID(),getMacro(), etc.