За последние 24 часа нас посетил 17841 программист и 1719 роботов. Сейчас ищут 950 программистов ...

Кеширование запросов, а зачем?

Тема в разделе "Прочие вопросы по PHP", создана пользователем Mr.M.I.T., 17 дек 2008.

  1. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    Сделал тут кеширование Sql запросов, быстрее работать скажем прямо не стало, хотя мб запрос простой и таблица маленькая, но всёже, а зачем оно - кеширование sql запросов?
    сам класс

    PHP:
    1. <?
    2.  
    3. class db {
    4.    private $link,$cache_dir,$lastident;
    5.    public $pref=false;
    6.    public $sqls,$insert_id,$afectrows,$lastquery;
    7.    public static $cnf;
    8.    private $CacheProc=array();
    9.    private $Cacher=array();
    10.    private $CacheResource=array();
    11.     function __construct() {
    12.       if (!self::$cnf) trigger_error("Ошибка: Не установлена переменная с конфигурациями \$cnf",E_USER_ERROR);
    13.         $this->link = mysql_connect(self::$cnf['db_host'],self::$cnf['db_user'],self::$cnf['db_pass'])
    14.                                     or $this->debug("Ошибка при подключении","Кофигурации:\r\n".print_r($cnf,1));
    15.         if (self::$cnf['db_encode'])
    16.             mysql_query('SET NAMES '.self::$cnf['db_encode']);
    17.         mysql_select_db(self::$cnf['db_name'],$this->link);
    18.         $this->pref=self::$cnf['db_pref'];
    19.     }
    20.     /*
    21.       Делает Запрос в БД
    22.       $sql - текст запроса
    23.       $ident - идент кеша, если кешируем
    24.       зы. возвращает либо ресурс если нет кеша, либо идент кеша
    25.     */
    26.     function Query($sql,$ident=false){
    27.        if($ident) {
    28.            if($this->is_cache($ident)) {
    29.                $this->NumRows=true;
    30.                return $ident;
    31.            }
    32.        }
    33.        $this->sqls++;
    34.        $sql=str_replace(array("?p","?P"),$this->pref,$sql);
    35.        $this->lastquery=$sql;
    36.        $sql=mysql_query($sql) or $this->debug("Ошибка при выполнении Sql запроса в методе Query","Запрос: ".$this->lastquery);
    37.        $this->lastident[$this->sqls]=$ident; // ключем лучше сделать ID ресурса
    38.        return $sql;
    39.    }
    40.    /*
    41.       Возвращает массив с результатами
    42.       $result - ресурс запроса или идент кеша
    43.       $cache_on - Включит кеш только для этого запроса, даже если в настройках кеширование отключено
    44.    */
    45.     function Fetch_array($result,$cache_on=0){
    46.        $arr=array();  // по дефолту вернём array()
    47.        if(is_resource($result)) { // если ресурс
    48.           $arr=mysql_fetch_assoc($result); // получаем массив
    49.           if($cache_on || self::$cnf['cache_on'])  // если кеширование включено
    50.              $this->CacheProc[$this->lastident[$this->sqls]][]=$arr;  // кешируем, пока в переменную
    51.        }else {  // а если не ресурс
    52.           if(empty($this->CacheResource))
    53.              $this->CacheResource=$this->CacheQuery($result); // делаем запрос кеша
    54.           if($this->CacheResource){
    55.              $arr=$this->CacheResource[0]; // берём первый элемент из кеша
    56.              unset($this->CacheResource[0]); // удаляем его в кеше
    57.              $this->CacheResource=array_values($this->CacheResource); // обновляемся
    58.           }
    59.        }
    60.         return $arr;
    61.     }
    62.     function Result($result) {
    63.        return mysql_result($result,0);
    64.     }
    65.     function Result_query($sql) {
    66.         $sql=$this->query($sql);
    67.         if ($sql)
    68.             return $this->result($sql);
    69.         return false;
    70.     }
    71.     /*
    72.       Вернёт массив с результатами запроса $sql
    73.     */
    74.     function Super_query($sql,$ident=false,$cache_on=0) {
    75.         if($res=$this->CacheQuery($ident))
    76.            return $res;
    77.         $res=array();
    78.         $sql=$this->query($sql);
    79.         while($row=$this->fetch_array($sql)) {
    80.              $res[]=$row;
    81.         }
    82.         if($ident && ($cache_on || self::$cnf['cache_on']))
    83.            $this->CacheProc[$ident]=$res;
    84.         return $res;
    85.     }
    86.  
    87.     function Inset_id() {
    88.         return $this->insert_id;
    89.     }
    90.     function NumRows($sql) {
    91.         if(is_resource($sql))
    92.            return mysql_num_rows($sql);
    93.         else
    94.            return true;
    95.     }
    96.     function Afectrows() {
    97.         return $this->afectrows;
    98.     }
    99.     function SqlGetAllRows($table,$where=1) {
    100.         return $this->result_query("SELECT COUNT(*) FROM `{$this->pref}_$table` WHERE $where");
    101.     }
    102.     function SqlGetOneRow($table,$row,$where=1) {
    103.         return $this->result_query("SELECT `$row` FROM `{$this->pref}_$table` WHERE $where");
    104.     }
    105.     function SqlGetLine($table,$line,$where=1) {
    106.         return $this->fetch_array(
    107.                     $this->query("SELECT `$line` FROM `{$this->pref}_$table` WHERE $where LIMIT 1")
    108.                                  );
    109.     }
    110.     function SqlGetLines($table,$where=1) {
    111.         return $this->fetch_array(
    112.                     $this->query("SELECT * FROM `{$this->pref}_$table` WHERE $where LIMIT 1")
    113.                                  );
    114.     }
    115.     function SqlGetAllLines($table,$where=1) {
    116.         return $this->super_query("SELECT * FROM `{$this->pref}_$table` WHERE $where");
    117.     }
    118.  
    119.     function InsertInto($table,$value) {
    120.         $ident=false;
    121.         if (!is_array($table) && is_array($value[0])) {
    122.             $values='';
    123.             for($i=0,$c=count($value);$i<$c;$i++) {
    124.                   $values.="("; $in='';
    125.                   foreach($value[$i] as $key=>$val) {
    126.                       if (is_string($key))
    127.                           $in.="`$key`,";
    128.                       $values.="'".mysql_real_escape_string($val)."',";
    129.                    }
    130.                  $values=substr($values,0,-1);
    131.                  $values.="),";
    132.                  if ($in) $in="(".substr($in,0,-1).")";
    133.             }
    134.             $values=substr($values,0,-1);
    135.             $ident=$this->query("INSERT INTO `".$this->pref."_".$table."` ".$in." VALUES ".$values);
    136.         }else if (!is_array($table) && is_array($value)) {
    137.             $values='';$in='';
    138.             foreach($value as $key=>$val) {
    139.                 $values.="'".mysql_real_escape_string($val)."',";
    140.                 if (is_string($key))
    141.                      $in.="`$key`,";
    142.             }
    143.             $values=substr($values,0,-1);
    144.             $values="($values)";
    145.             if ($in) $in="(".substr($in,0,-1).")";
    146.             $ident=$this->query("INSERT INTO `".$this->pref."_".$table."` ".$in." VALUES ".$values);
    147.         }else if(!is_array($table) && !is_array($value)) {
    148.            $ident=$this->query("INSERT INTO  `".$this->pref."_".$table."` VALUES ($value)");
    149.         }
    150.         $this->afectrows=mysql_affected_rows();
    151.         return $ident;
    152.     }
    153.  
    154.     function Update($table,$value,$where=0) {
    155.          $ident=false;
    156.          if (!is_array($table) && !is_array($value)) {
    157.              $ident=$this->query("UPDATE ".$this->pref."_".$table." SET ".$value." ".($where?"WHERE $where":""));
    158.          }else if (!is_array($table) && is_array($value)) {
    159.              $sql="UPDATE ".$this->pref."_".$table." SET ";
    160.              for($i=0,$c=count($value);$i<$c;$i++) {
    161.                  $sql.="{$value[$i]}".($i!==$c-1?",":"");
    162.              }
    163.             if ($where)
    164.                $sql.=" WHERE $where";
    165.             $ident=$this->query($sql);
    166.          }
    167.          $this->afectrows=mysql_affected_rows();
    168.          return $ident;
    169.      }
    170.     function Del($table,$value) {
    171.          $ident=false;
    172.          if (!is_array($table) && !is_array($value)) {
    173.              $ident=$this->query("DELETE FROM ".$this->pref."_".$table." WHERE ".$value);
    174.          }else if (!is_array($table) && is_array($value)) {
    175.              $sql="DELETE FROM ".$this->pref."_".$table." WHERE ";
    176.              for($i=0,$c=count($value);$i<$c;$i++) {
    177.                  $sql.=$value[$i].($i!==$c-1?" OR ":"");
    178.              }
    179.          }
    180.          $this->afectrows=mysql_affected_rows();
    181.          return $ident;
    182.      }
    183.     function Delet($table,$value) {
    184.         return $this->Del($table,$value);
    185.     }
    186.     function debug($msg,$upinfo='') {
    187.         print "
    188.           <h4>$msg</h4>
    189.           <hr>
    190.           <b>MysqlError:</b>".(!mysql_error()?"None":mysql_error())."<br>
    191.           <b>Errorno:</b>".(mysql_errno()?mysql_errno():"None")."
    192.           ".($upinfo?"<hr><b>Дополнительно:</b><br><textarea cols=70 rows=7>$upinfo</textarea>":"")."
    193.        ";
    194.         exit;
    195.     }
    196.     /*
    197.        Вернёт папку с кешем
    198.     */
    199.     private function GetCacheDir($ident) {
    200.         if (!$this->cache_dir[$ident])
    201.             $this->cache_dir[$ident]=$_SERVER['DOCUMENT_ROOT']."/".self::$cnf['cache_dir'].'/'.md5($ident).".sql.php";
    202.         return $this->cache_dir[$ident];
    203.     }
    204.     /*
    205.       Запрос кеша по иденту,
    206.       вернёт массив с результатами как при super_query или false в случае неудачи
    207.     */
    208.     function CacheQuery($ident) {
    209.           if(!$ident) return false;
    210.           $file=$this->GetCacheDir($ident);
    211.           if($this->is_cache($ident)){
    212.                   if(!$this->Cacher[$ident]){
    213.                      include $file;
    214.                      $this->Cacher[$ident]=$__ARRAY;
    215.                   }
    216.                   return $this->Cacher[$ident];
    217.           }else {
    218.              if(file_exists($file))
    219.                 unlink($file);
    220.           }
    221.           return false;
    222.     }
    223.     /*
    224.       Жив ли ещё кеш?
    225.     */
    226.     function CacheLifeEnd($ident){
    227.         if(time()-filemtime($this->GetCacheDir($ident))<=self::$cnf['cache_time'])
    228.            return false;
    229.         return true;
    230.     }
    231.     /*
    232.       Существует ли кеш?
    233.     */
    234.     function is_cache($ident) {
    235.         $file=$this->GetCacheDir($ident);
    236.         if(file_exists($file)
    237.               && !$this->CacheLifeEnd($ident))
    238.                    return true;
    239.         return false;
    240.     }
    241.     /*
    242.       Сохраняет кеш в файлы
    243.     */
    244.     private function CacheSave() {
    245.         if($this->CacheProc) {
    246.             foreach($this->CacheProc as $ident=>$arr) {
    247.                 $filedir=$_SERVER['DOCUMENT_ROOT']."/".self::$cnf['cache_dir']."/".md5($ident).".sql.php";
    248.                 @file_put_contents(
    249.                                $filedir,
    250.                                "<? \$__ARRAY=".$this->FormArray($arr)."?".">")
    251.                                   or $this->debug("Ошибка, Не могу сохранить файл с кешем",
    252.                                                     "FileDir:$filedir\r\nFileIdent:$ident");
    253.             }
    254.         }
    255.     }
    256.     private function FormArray($arr) {
    257.       $res=array();
    258.       if(empty($arr))
    259.          return "array()";
    260.          foreach($arr as $key=>$val) {
    261.              if(!is_array($val)){
    262.                 $res[]="\"$key\"=>\"$val\"";
    263.              } else {
    264.                 $res=array_merge($res,array($this->FormArray($val)));
    265.              }
    266.          }
    267.       return "array(".implode(",",$res).")";
    268.     }
    269.     function __destruct() {
    270.         $this->CacheSave();
    271.     }
    272. }
    273.  
    274.  
    275.  
    276.  
    277.  
    278.  
    279.  
    280. db::$cnf=array(
    281.           "db_name"=>"test",
    282.           "db_user"=>"root",
    283.           "db_pass"=>"",
    284.           "db_host"=>"localhost",
    285.           "db_encode"=>"cp1251",
    286.           "db_pref"=>"test",
    287.           "cache_time"=>"60",
    288.           "cache_dir"=>"sqlcache",
    289.           "cache_on"=>0,
    290.            );  // Настройки
    291. $db=new db();
    292. $sql=$db->query("SELECT * FROM ?p_test","somesql");
    293. $res=array();
    294. if($db->numrows($sql)) { // если чёто вернулось
    295.   while($row=$db->fetch_array($sql,1)) { // получаем инфу их кеша или из БД
    296.       $res[]=$row;
    297.   }
    298.   print_r($res);
    299. }else {
    300.    print "Stop Stop";
    301. }
    302. ?>
     
  2. Смысл кеша в сложных запросах, которые ребуют сложных пересечений, выполняются достаточно часто, но при этом, данные меняются достаточно редко.
     
  3. AlexGousev

    AlexGousev Активный пользователь

    С нами с:
    25 мар 2006
    Сообщения:
    1.505
    Симпатии:
    0
    Адрес:
    Москва
    Mr.M.I.T.
    В MySQL есть кеш запросов. Имеет смысл делать кеш не запросов, а уже сформированных кусков данных или всей страницы целиком.
     
  4. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    Это другая тема =)

    ну вот тут Олег сказал, что имеет смысл делать кеш только сложных запросов, пожалуй это всё что я хотел услышать =))
    А по теме кеша в мускуле, не знаю какой он там, но некоторый запросы по секунде, заставляют задуматься...

    А кстати, какая функция возвращает id mysql ресурса или что-то в этом роде...
     
  5. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    не изобретайте кривой трехколесный велосипед.
    люди давно ездят на memcache

    кеш он для чего нужен? что б скрипты быстрее работали, а скорость нужна там, где ее заранее умные люди проектируют и закладыают на тех решениях, которые дают прирост. а костыли типа этого, это заказчику втереть, что "разработчик" крутой.
     
  6. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    имеет смысл сначала продумать где нужно и можно сэконоить, делать ради деланья - глупость.
     
  7. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    =)
    не мешай мальчику самолюбоваться. видишь он "кеш" пишет, а какой и зачем сам не понимает.
     
  8. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    440Hz
    почти раскусил на счёт заказчика 0о
    естественно, раньше не занимался этим никогда =)

    А чёж тогда советуют то его все делать?
    Я тут двиг недавно презентовал, основная критика это отсутствие продвинутой системы кеширования, а я стоял как дурак и не знал что ответить...
    нет, только если буду делать свой, высоконагруженный проект.
     
  9. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    если те будут советовать головой об стенку биться - то ж будешь?

    надо понимать что и зачем кешируешь. нет смысла кешировать SQL и его ответы, если наружу ты выдаешь всего лишь HTML. Я, к примеру, кеширую (правда в memchahe) куски HTML и страницы собираются уже из готовых кусков. Быстро и со вкусом. На 100 тыс. проекте (dezinfo.net) время сборки полной страницы для отдачи 0.03 сек., хотя там есть SQL на 10-15 сек.

    в твоем случае кеш на файлах SQL запросов - милая шутка новичка и не более того.
     
  10. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    хм, ну вот ты мне щас советушь не делать велосипед ;)
    Там тоже достаточно опытные люди...

    дело в том что в некоторых местах у меня нельзя кешировать куски html, а хочецо...
    (например хочу кешировать комментарии, но там есть такое поле как быстрое администрирование, естественно не для всех пользователей, как быть?)
     
  11. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    я храню кеш с разделением по пользхователям и страницам, а вообще, какой ключ захочешь такой и делай для хранения. это твое полное право, а кеш должен просто данные тебе отдать.

    например

    name.userid.page и т.д.
     
  12. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    конкрето где и кто?
     
  13. AlexGousev

    AlexGousev Активный пользователь

    С нами с:
    25 мар 2006
    Сообщения:
    1.505
    Симпатии:
    0
    Адрес:
    Москва
    А кто советует делать кеш запросов? Ну сам подумай, зачем тебе данные запроса в необработанном и неготовом для вывода виде?

    Там, где нельзя или логика кеширования слишком сложна - не кешируй. А там где можно - кешируй. Потому и говорю, что можно кешировать куски, а можно страницу целиком: зависит от ситуации.
     
  14. AlexGousev

    AlexGousev Активный пользователь

    С нами с:
    25 мар 2006
    Сообщения:
    1.505
    Симпатии:
    0
    Адрес:
    Москва
    Плюс есть кеширование на стороне пользователя: управление этим кешем тоже может дать результаты.
    В CMS'ках вообще зачастую тупо делается "эта страница не будет обновляться еще 5 минут". Такой кеш местами оправдан.
    Соответственно, и страница берется из кеша, и клиенту отдается заголовок, что не обращайся за этой страницей еще 5 минут: бери из своего кеша.
    Там, где нужна точность зависимости информации от времени, можно управлять кешем пользователя на основе Last-Modified и E-tag.
     
  15. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    ну да, забыл сказать что мне нужно на файлах, мэмкешед нельзя по закрытым для разглашения пичинам =)
    а, не скажу :twisted:
    не, не буду говорить вдруг они щас это читают...
    ну скажем это опытные топ фрилансеры, директор айти компании, преподы в престижных ввузах, вроде кто-то даже на конференции хай-лоад выступает...
    я их не знаю пока...
     
  16. Есть выражение... Слышал звон... ))
     
  17. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    еслиб всё было так просто...
     
  18. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    это те, кто 99% ниче не понимает в кешировании, а при слове "кеширование" делают умное лицо и кивают головой, мол "одобрям"!
    =)

    повторюсь, если те в ЦМС или где еще нужен КЕШ для втирания заказчикам или кому-то там еще. так НАМ и скажи. Мы поймем, а вот ВТИРАТЬ НАМ мозги не надо. Не прокатит.
     
  19. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    скажем мне нужно что-то ответить когда мне начнум втирать почему у меня его нет, да так ответить, чтобы не оспорить
    а ЛИЧНО для себя мне нужно чтобы быстро работало, вот как dezinfo например ;) но желательно всё равно без мэмкешеда...
    понимают не понимают, а они рулят всей этой отраслью...
     
  20. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    я бы говорил всем, что моя систем нстолько быстрая что кеш ей ненужен и пусть ОНИ доказывают что он мне нужен.

    написать систему которая работет 100% быстро во всех применениях НЕВОЗМОЖНО.

    и вообще есть золотое правило:

    оптимизировать нужно тогда, когда тормозит. до этого все заявления об оптимизации сливаются в ноль.

    посему законный вопрос - где у тебя тормозит? чай не в голове?
     
  21. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    дак тормозит понятие растяжимое, один запрос у меня 0.5 сек условно, а другой 1, а я хочу уложится на весь вывод в 1 секунду, вот и тормозит...
    а вообще, я когда что-то делаю стараюсь думать наперёд, так что надо думать Где БУДЕТ тормозить...а в запросах тормозить будет 100%
     
  22. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    ессесно, но кеш-то тут причем?
    =)

    говорят же тебе. кешировать надо для начала HTML, а SQL не торогай... вот этим и займись.
     
  23. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    html - кеширует, но только статику, надо динамику.
    ну ТиПа должно быстрее работать если запрос сложный...?
     
  24. 440Hz

    440Hz Старожил
    Команда форума Модератор

    С нами с:
    21 дек 2012
    Сообщения:
    8.003
    Симпатии:
    1
    Адрес:
    Оттуда
    думать ингода тоже ТиПа надо...

    лана. тебе про кеш вродже объяснили. хочешь SQL кешировать - кешируй... удиви топ-менеджеров новым нюансом.
    гыгыгы
     
  25. Mr.M.I.T.

    Mr.M.I.T. Старожил

    С нами с:
    28 янв 2008
    Сообщения:
    4.586
    Симпатии:
    1
    Адрес:
    у тебя канфетка?
    440Hz
    У меня есть идея получше, я буду всем говорить типа "Лугов сказал" ггг
    SQL кеш всётаки сделаю на самом тяжёлом запросе, поставлю обновление кеша не минуту, посмотрим что получится...