Portal > Foren > PHP > PHP-Programmierung > Cachen von SQL-Queries. Sinnvoll?
Antwort
 
Themen-Optionen Thema durchsuchen
Alt 12.11.2005, 23:24 Nach oben    #1
Ben
Benjamin Klaile
 
Benutzerbild von Ben
 
Registriert seit: 02.12.2004
Ort: Remagen
Beiträge: 4.516
Standard Cachen von SQL-Queries. Sinnvoll?

Hi,
ich habe soeben auf Zend.com dieses Tutorial hier gefunden:
SQL Query Caching

Ich wollte jetzt mal fragen, ob da jemand Erfahrung mit hat. Mir geht es da vor allem darum, ob sich das Caching überhaupt lohnt.
ist es günstiger "eine" Datenbankabfrage durchzuführen oder eine Caching-Technik anzuwenden?

Freu mich auf Antworten .
Grüße Ben.


PS:
Bitte auch die Kommentare beachten
Ben ist offline  
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 13.11.2005, 07:27 Nach oben    #2
Goldman.de
 
Benutzerbild von J33d3X
 
Registriert seit: 09.10.2005
Ort: Frankfurt am Main
Beiträge: 190
Standard

warum steht denn bei bsp. ebay das eine verzögerung von 3min sein kann
( da deren cacheengine auf 3 min(max) steht

wenn nur 10 querys pro tag dann sicher nicht ansonsten durchaus
ich nutze dazu die Cacheengine von PEAR wobei ich das Statement getrennt vom result cache

da ich ja eh mit einer dbklasse arbeite ist das cachen hier sehr einfach
kleines beispiel
PHP-Code:
<?php

    
// }}}
    // {{{ getNums()

    /**
     * - Execute mysql_num_rows with parameters
     * 
     * @param string $table Tablename
     * @param string $para whereclausel
     * @param string $col selected column
     * @return integer COUNT
     * @access public
     */
    
function getNums($table$para$field=false)
    {
        global 
$objCACHE;
        
        
$err    false;
        
$field  false==$field '*' $field;
        
$return false;
        
        
$cacheId=$objCACHE->generateID("SELECT COUNT($field) as return FROM ".PRE."$table $para");
        if (
true==$objCACHE->get($cacheIdSQL_STATEMENTS))
        {
            return 
$objCACHE->get($cacheIdSQL_RESULTS);
        }
        
$objCACHE->save($cacheId,"SELECT COUNT($field) as return FROM ".PRE."$table $para"EXP_CACHE_TIMESQL_STATEMENTS);
        
        
$sql=$this->query("SELECT COUNT($field) as num FROM ".PRE."$table $para");
            if (
true==mysql_error())
            {
                
$err=Error_class::raiseError('getNums:<br />'.mysql_error(),2,'',__FILE__,get_class($this),__LINE__);
                
Error_class::errorHandling($err);
            }
            else
            {
                
$return=$this->fetch_assoc($sql);
            }
        
$objCACHE->save($cacheId,$return['num'], EXP_CACHE_TIMESQL_RESULTS);
        return 
$return['num'];
    }
?>

hier ein einfaches sql-cache beispiel

PHP-Code:
<?php 

class sqlCache

{

   
// Initialisieren der benoetigten Werte

   
var $server="localhost";

   var 
$user="xx";

   var 
$password="xx";

   var 
$database="xx";

   

   var 
$data=array();  // Speichert die Daten aus der Abfrage

   
var $filename='';  // Enthaelt den Namen der Cache-Datei

   

   // Konstruktor der Klasse

   // Initialisiert das Objekt

   // $expire ist die Gueltigkeitsdauer des Caches in Sekunden

   // $query_data ist ein Array mit Suchbegriffen

   
function sqlCache($expire$query_data)

   {

      
// Sortiert Suchbegriffe alphabetisch fuer den Dateinamen

      
sort($query_data);

      
// erstellt den Dateinamen

      
$this->filename=implode("_",$query_data).".dat";

      
$this->filename=strtolower($this->filename);

      
// Cache loeschen, damit filemtime() korrekt arbeitet

      
clearstatcache();

      
// Existiert Cache-Datei und ist sie gueltig? => Cache-Hit

      
if ((true==file_exists($this->filename)) &&

          (
time()-$expire) <= filemtime($this->filename)

         )

      {

         
// Ja, wir haben einen Hit => Datei einlesen

         
$raw_data=file_get_contents($this->filename);

         
// Die ersten 32 Byte sind der md5-Hash

         
$md5=substr($raw_data,0,32);

         
// Restliche Daten separieren

         
$ser_data=substr($raw_data,32);

         
// Gelesene Daten OK?

         
if ($md5 != md5($ser_data))

         {

            
// Daten nicht OK, Datenbank abfragen

            
$this->_queryData($query_data);

         }

         else 

         {

            
// Daten sind OK => entpacken

            
$this->data=unserialize($ser_data);

         }

      }

      else

      {

         
//Cache-Miss => Cache-File war nicht aktuell 

         // oder nicht angelegt => Daten abfragen

         
$this->_queryData($query_data);

         
// Cache-Datei schreiben

         
$this->_makeFile();

      }

   }



   

   function 
_queryData($query_data)

   {

      
// Verbindung zur Datenbank oeffnen

      
$db=mysql_connect($this->server,

                        
$this->user,

                        
$this->password);

      
mysql_select_db($this->database,$db);



      
// SQL-Befehl konstruieren

      
$bed1=implode("%'OR titel LIKE '%",$query_data)."%' ";

      
$bed2=implode("%'OR beschreibung LIKE '%"

                                         
$query_data)."%' ";



      
$sql="SELECT titel,beschreibung,bidder FROM auktionen 

               WHERE (

                  titel LIKE '%$bed1 

                  OR beschreibung LIKE '%$bed2)"
;

      
// Abfrage zur Datenbank

      
$query_result=mysql_query($sql,$db);

      if (
false===$query_result)

      {

         die (
"Fehler in Abfrage<br />".mysql_error());

      }

      
mysql_close($db);

      
// Alle Daten auslesen und in Array speichern

      
while ($zeile=mysql_fetch_row($query_result))

      {

         
$this->data[]=$zeile;

      }



   }

   

   function 
_makeFile ()

   {

      
// Daten packen, um sie speichern zu koennen

      
$ser_data=serialize($this->data);

      
// md5-Hash berechnen

      
$md5=md5($ser_data);

      
// In PHP5 koennen Sie alternativ 

      // file_put_contents($this->filename, “$md5$ser_data”-) 

      // nutzen

      
$fp=fopen($this->filename,"w");

      if (
false==$fp)

      {

         die (
"Konnte Cache-Datei nicht anlegen");

      }

      
// md5-Hash speichern

      
fwrite ($fp,$md5); 

      
// Serialisierte Daten speichern        

      
fwrite ($fp,$ser_data);

      
fclose($fp);

   }

   

}



// Cache-Datei soll 60 Sekunden gueltig sein

$expire=60;

// Suchbegriffe, die der Benutzer eingegeben hat

$daten=array("corrado","vw");

// Neues Cache-Objekt für diese Suchbegriffe erzeugen

$sql_result=new sqlCache($expire,$daten);

// Daten aus $sql_result->data weiterverarbeiten.  

?>

mfg

Geändert von J33d3X (13.11.2005 um 07:30 Uhr)
J33d3X ist offline  
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 13.11.2005, 10:03 Nach oben    #3
Corvin Gröning
 
Benutzerbild von Corvin
 
Registriert seit: 19.03.2005
Ort: S-H | Flensburg
Beiträge: 459
Standard

Zitat:
Zitat von Ben
ist es günstiger "eine" Datenbankabfrage durchzuführen oder eine Caching-Technik anzuwenden?
Wie J33d3X schon schreibt, bei 10 Querys pro Tag lohnt sich ein Query-Caching sicher nicht. Bei vielleicht 1000 und mehr Querys pro Tag lohnt sich das schon eher. Wenn nur alle 5 Minuten eine Query ausgeführt wird und ansonsten die Daten aus einer Datei gelesen werden, entlastet das den Server.
__________________
Corvin ist offline  
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.11.2005, 16:27 Nach oben    #4
axo
Gast
 
Beiträge: n/a
Standard

http://dev.mysql.com/doc/refman/4.1/en/query-cache.html

mysql optimiert also, korrekt eingerichtet und eine aktuelle version vorausgesetzt, bereits ganz gut - besser als alles, was man auf den 'zend'-seiten als sog. knowledge vermittelt bekommt - ich wage es zu bezweifeln, dass unserialize() eines größeren datensatzes schneller ist als das query cache von mysql.

meine erfahrung ist:
es sind nicht unbedingt die mysql-abfragen, die 'langsam' sind, sondern eher das parsen der template-engines und das erzeugen des html-outputs. langsame mysql-abfragen lassen sich bereits mit leichten index-spielen oft optimieren, die 'geschwindigkeit' von php aber nicht.

ergo:
nicht die abfrage selbst cachen, sondern den kompletten html-output... d.h. bei einem 'cache miss' die seite erzeugen und die ausgabe zwischenspeichern, bei einem 'cache hit' einfach die bereits fertige html-seite aufrufen - ob per include oder sonstwie ist dann auch egal.
hätte im prinzip auch den vorteil, dass man die statischen oder cache-seiten ziemlich trivial mit proxies implementieren kann - und damit z.b. einen oder mehrere cache-server vor den php-server zu schalten, die sich nur um die ausgabe der 'cache'-seiten kümmern.
damit ist die skalierbarkeit mit hardware gewährleistet und die ist, aktuellen zahlen zufolge, billiger als software-optimierungen.

Geändert von axo (14.11.2005 um 16:33 Uhr)
 
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 14.11.2005, 16:39 Nach oben    #5
Ben
Benjamin Klaile
 
Benutzerbild von Ben
 
Registriert seit: 02.12.2004
Ort: Remagen
Beiträge: 4.516
Standard

Zitat:
Zitat von axo
nicht die abfrage selbst cachen, sondern den kompletten html-output
Yeah. Genauso mach ich das derzeit auch.
Ben ist offline  
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Alt 19.11.2005, 14:05 Nach oben    #6
Jay
Gast
 
Beiträge: n/a
Standard

Ich habe mir meinen eigene kleinen Cache geschrieben:
PHP-Code:
<?php
class Cache
{
    
/**
     * Location where cache files are stored
     * @var storeFiles string
     */
    
private static $storeFiles './cache/';
    
    
/**
     * Stores the cached data in a file
     * @param group string - A group to which the cached file belongs to
     * @param uniqueId int - A unique id for each cached file
     * @param data string - Th data to save in the file
     */
    
public static function writeFile($group,$uniqueId,$data)
    {
        
$filename self::getFilename($group,$uniqueId);

        if (
$fp fopen($filename,'xb'))
        {
            if (
flock($fp,LOCK_EX))
            {
                
fwrite($fp,$data);
            }
            
fclose($fp);
            
            
touch($filename); // Set time
        

    }
    
    
/**
     * Creates the filename. Not the file!
     * @param group string - A group to which the cached file belongs to
     * @param uniqueId int - A unique id for each cached file
     */
    
protected static function getFilename($group,$uniqueId)
    {
        return 
self::$storeFiles.$group.'_'.md5($uniqueId);
    }
    
    
/**
     * Gets the content of a cached file
     * @param group string - A group to which the cached file belongs to
     * @param uniqueId int - A unique id for each cached file
     *
     * @return string
     */
    
public static function readFile($group,$uniqueId)
    {
        
$filename self::getFilename($group,$uniqueId);
        
        
$data file_get_contents($filename); // Get's the data of the file
        
        
return unserialize($data); // return the data
    
}
    
    
/**
     * Checks if a file is cached or not
     * @param group string - A group to which the cached file belongs to
     * @param uniqueId int - A unique id for each cached file
     * @param cacheTime int - The caching time in seconds
     *
     * @return boolean
     */
    
protected static function isCached($group,$uniqueId,$cacheTime)
    {
        
$filename self::getFilename($group,$uniqueId);
        
// if the file is cached

        
if (file_exists($filename) && filemtime($filename)+$cacheTime >= time())
        {
            return 
true;
        }
        
// if the file is not cached or antiquated
        
@unlink($filename);
        return 
false;
    }
}

class 
Caching extends Cache
{
    
/**
     * The group name
     * @var gr string
     */
    
protected static $gr;
    
    
/**
     * The uniqueId
     * @var int
     */
    
protected static $id;
    
    
/**
     * This method starts the cache
     * @param group string - A group to which the cached file belongs to
     * @param uniqueId int - A unique id for each cached file
     * @param cacheTime int - The caching time in seconds
     *
     * @return boolean
     */
    
public static function start($group,$uniqueId,$cacheTime 7200)
    {
        
// if the file is cached
        
if (self::isCached($group,$uniqueId,$cacheTime))
        {
            echo 
self::readFile($group,$uniqueId);
            return 
false;
        }
        else
        {
            
ob_start();
            
self::$gr $group;
            
self::$id $uniqueId;
            
            return 
true;
        }
    }
    
    
/**
     * Stops caching
     */
    
public static function stop()
    {
        
// Get the puffered data
        
$data ob_get_contents();
        
// write the data in the file

        
self::writeFile(self::$gr,self::$id,serialize($data));
    }
}
?>
Beispiel:
PHP-Code:
if (Caching::start('sample',01,7200)) {
    
// Hier die SQL queries oder Funktionsaufrufe
    
Cacheing::stop();

Funktioniert super und ist schnell. Wenn man am Anfang eines Scripts ob_start() oder ob_start('gz_handler') aufruft. Wird das Script nochmal deutlich schneller. Dann noch einen Cache.

Dann z.B. noch Code optimieren:
PHP-Code:
// Würde man mit einer while Schleife machen
for ($i 0$i<mysqli_num_rows($result); ++$i) {
  
// Hier wird bei jedem durchlauf die Funktion mysqli_num_rows() aufgerufen  
}

// Optimierte Version
$numRows mysqli_num_rows($result);
for (
$i 0$i<$numRows; ++$i) {
   
// Hier werden einfach zwei Variablen verglichen => deutlich schneller

Man kann auch OPCODE Caches verwenden oder sich einen Query Cache in C schreiben.
 
Diesen Beitrag zu to del.icio.us hinzufügen!Diesen Beitrag zu Technorati hinzufügen!Diesen Beitrag zu Mister Wong hinzufügen!
Mit Zitat antworten
Antwort

Lesezeichen


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks sind an
PingBacks sind an
RefBacks sind aus

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
Abkürzung des Wochentags in SQL, vgl. strftime in PHP Ben Datenbanken 4 12.04.2007 16:51
Smarty - Dynamische Seiten cachen? dsxs PEAR, PECL und Frameworks 5 26.09.2006 19:36
[Rezension] Professionelle PHP 5-Programmierung, Ben Literatur 11 27.07.2006 20:48
Zugriff auf Wert des vorhergenden Datensatzes in einer SQL Abfrage Jay Datenbanken 5 17.07.2006 15:25
HTMLKlasse sinnvoll oder überflüssig? Chr!s PHP-Programmierung 6 07.05.2006 15:59


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:58 Uhr.


Powered by vBulletin® Version 3.7.4 (Deutsch)
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45