2010-06-21 3 views
0

J'utilise Zend_Cache_Core avec Zend_Cache_Backend_File pour mettre en cache les résultats des requêtes exécutées pour une classe de modèle qui accède à la base de données.Générer un identifiant unique pour une chaîne donnée en utilisant php

Fondamentalement les requêtes elles-mêmes devraient former l'id par lequel mettre en cache les résultats obtenus, le seul problème est, ils sont trop longs. Zend_Cache_Backend_File ne lance pas d'exception, PHP ne se plaint pas mais le fichier cache n'est pas créé.

Je suis venu avec une solution qui n'est pas efficace du tout, le stockage toute requête exécutée avec un identifiant autoincrementing dans un fichier séparé comme ceci:

0 - >> SELECT * FROM table 1- >> SELECT * FROM table1, table2 2 - >> SELECT * FROM table OERE foo = bar

Vous avez l'idée; De cette façon, j'ai un identifiant unique pour chaque requête. Je nettoie le cache chaque fois qu'une insertion, suppression ou mise à jour est effectuée.

Maintenant, je suis sûr que vous voyez le goulot d'étranglement potentiel ici, pour tout test, enregistrer ou récupérer du cache deux (ou trois, où nous devons ajouter un nouvel ID) demandes sont faites au système de fichiers. Cela peut même vaincre le besoin de mettre en cache tous ensemble. Donc est-il possible de générer un identifiant unique, c'est-à-dire une représentation beaucoup plus courte, des requêtes en php sans avoir à les stocker sur le système de fichiers ou dans une base de données?

Répondre

1

Les chaînes sont arbitrairement longues, donc il est évidemment impossible de créer un identificateur de taille fixe qui peut représenter n'importe quelle chaîne d'entrée arbitraire sans duplication. Cependant, à des fins de mise en cache, vous pouvez généralement vous débarrasser d'une solution «assez bonne» et réduire les collisions à un niveau acceptable. Par exemple, vous pouvez simplement utiliser MD5, qui ne produira une collision que dans les cas 1-en-2 sur 010. Si vous êtes toujours inquiet des collisions (et vous devriez probablement être, juste pour être sûr), vous pouvez stocker la requête et le résultat dans la "valeur" du cache, et vérifier quand vous obtenez la valeur que c'est en fait la requête que vous cherchiez.

Comme un exemple rapide (mon PHP est un peu rouillé, mais nous espérons que vous avez l'idée):

$query = "SELECT * FROM ..."; 

$key = "hash-" + hash("md5", $query); 
$result = $cache->load($key); 
if ($result == null || $result[0] != $query) { 
    // object wasn't in cache, do the real fetch and store it 
    $result = $db->execute($query); // etc 

    $result = array($query, $result); 
    $cache->save($result, $key); 
} 

// the result is now in $result[1] (the original query is in $result[0]) 
+0

Merci! J'essaie ça en ce moment. Deux questions. Je pensais que le hachage devrait produire le même résultat quand on donne la même chaîne d'entrée encore et encore. Est-ce pas correct? Quelle sera la longueur du hash md5, parce que je pense que les requêtes elles-mêmes ont été rejetées en tant qu'ID par le système d'exploitation en raison de la longueur des noms de fichiers résultants? Merci, je l'essaie, mais il y aura quelques endroits à refactoriser, donc cela prend du temps. Je savais que je devais mettre en cache la requête avec le résultat ne pouvait pas comprendre comment! – Joey

+0

J'ai trouvé les réponses aux deux questions dans le commentaire précédent et j'ai posté la réponse ci-dessous. Mais je ne suis toujours pas sûr des collisions avec md5 hash, quelqu'un s'il vous plaît m'expliquer cela. – Joey

+0

@Joey: Utiliser MD5 avec la même chaîne produira toujours la même sortie, mais le problème est qu'il y a 1 chance sur 2^128 que deux chaînes * différentes * produisent aussi la même sortie. Il est donc possible (bien que peu probable) que deux requêtes différentes hachent la même clé MD5. C'est pourquoi j'ai ajouté la vérification supplémentaire: pour s'assurer que cela n'arrive pas. –

0

MD5 !! Md5 génère une chaîne de longueur 32 qui semble fonctionner correctement, les fichiers de cache sont créés (avec des noms de fichiers de longueur 47), il semble donc que le système d'exploitation ne les rejette pas.

//returns id for a given query 
function getCacheId($query) { 
    return md5($query); 
} 

Et c'est tout! Mais il y a cette question de collisions et je pense que saler le hachage MD5 (peut-être avec le nom de la table) devrait le rendre plus robuste.

//returns id for a given query 
function getCacheId($query, $table) { 
    return md5($table . $query); 
} 

Si quelqu'un veut le code complet de la façon dont je l'ai mis en œuvre la mise en cache des résultats, il suffit de laisser un commentaire et je serai heureux de le poster.

Questions connexes