Цитата мудреца

Голосование

Система Orphus. Если вы заметили ошибку на сайте, нажмите сюда.
Загружается, подождите...
Начало сайта Материалы сайта Программы PHP-скрипты
Версия для слабовидящих
Версия для печати

Кэширование запросов MySQL

Здесь представлены некоторые мои разработки на PHP. Это в, основном, служебные скрипты, которые работают в составе других скриптов и не могут быть протестированы здесь непосредственно.

Время к скрипту и так прикручено. Проверяется время создания файла с кэшем и сравнивается с параметром валидности при вызове. Если файл старее, чем переданный параметр, то файл переписывается, но не удаляется. Ибо он опять нужен.
Но скрипт никак не будет знать, какой именно файл надо удалять, потому что имя файла - хэш самого запроса.
Если же при каждом вызове скрипта вставлять проверку всей директории и смотреть, какие файлы стали старыми, то никакого выигрыша в скорости не будет. Такое удаление должно происходить раз в час/сутки по инициативе либо крона, либо запускаться из какой-то специальной странице, при заходе на неё или вообще вручную.
Ответить


Андрей, првиет!

тут ваяю сайтик, с использованием твоего кэшера, о этому решил задачку удаления старых кэшей таким образом:
1) создаю БД (для того, что бы не нарушать отчетности :) )
Код: Выделить всё
--
-- Структура таблицы `log_peak_sql_query`
--

CREATE TABLE `log_peak_sql_query` (
  `id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'Номр записи',
  `peak_date_year` int(4) NOT NULL COMMENT 'Год запроса',
  `peak_date_month` enum('1','2','3','4','5','6','7','8','9','10','11','12') NOT NULL COMMENT 'Месяц запроса',
  `peak_date_day` enum('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') NOT NULL COMMENT 'День запроса',
  `peak_time` time NOT NULL COMMENT 'Время запроса',
  `peak_exec` float(14,12) NOT NULL COMMENT 'Время работы БД по запросу',
  `peak_query` tinytext NOT NULL COMMENT 'Запрос к БД',
  `peak_script` tinytext NOT NULL COMMENT 'Скрипт, выполняющий запрос',
  PRIMARY KEY (`id`),
  KEY `peak_date_month` (`peak_date_month`,`peak_date_day`),
  KEY `peak_date_year` (`peak_date_year`),
  KEY `peak_date_day` (`peak_date_day`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='Таблица пиковой нагрузки при SELECT-обращении к БД';

2) вторым пунктом своих развлечений наваял простейший скрипт, что будет заностить данные в БД и удалять весь кэш (только txt-файлы):
Код: Выделить всё
<?php
/*
 * Данный скрипт предназначен для ежедневного формирования файла нагрузки по
 * запросам к БД. А так же удаляет все кэшированные запросы к БД.
 */
////////////////// Тут нужно заменить одну часть условия, догадались какую? :)
////////////////// Ну и конечно же проставить до : и после него пути к папкам конфиг-файлов.
//  формируем путь к файлу кофигурации и подключаем его.
$path = (getenv('HTTP_HOST')=='ВАШ_САЙ_НА_ЛОКАЛЬНОМ_КОМПЕ') ? './' : './public_html/';
// Подключаю конфиг файла, в котором прописан путь до папки с кэшем и автолоадер классов
require_once $path . 'config.php';

//  Производим разбор пикового файла и запись его в общий лог.
$peak_filename = CACHE . '!peak.txt';
//  открываем файл для чтения
if (@$file = fopen($peak_filename, 'r'))   {
   flock($file, LOCK_SH);
   $fdata = file($peak_filename);
   foreach ($fdata as $key => $value)   {
      $peak[$key] = trim($value);
   }
}
//  если файл был успешно открыт, то закроем файл.
if ($file)   {
      fclose($file);
}

//  время отработки запроса
$peak_exec = floatval($peak[0]);
//  Дата и время запроса
//  Поскольку формат даты фремени не совпадает с MySQL, то преобразуем его.
$peak_data_file = $peak[1];
//  Делим на подстроки через пробелы:
//  0 - день недели с запятой в конце - отбрасываем
//  1 - день в месяце (число)
//  2 - месяц (название, нужно перевести в число)
//  3 - год
//  4 - время
//  5 - поправка времени по отношению к гринвичу - отбрасываем
$peak_data_file = explode(' ', $peak_data_file);
//  преобразуем месяц в число
$help_class = new my();
$peak_data_file[2] = $help_class->replaceEngCutMonthToNum($peak_data_file[2]);
//  теперь соберем в кучу только дату и время
$peak_data = $peak_data_file[3].'-'.$peak_data_file[2].'-'.$peak_data_file[1]
            .' '.$peak_data_file[4];
//  Запрос к БД
$peak_query = $peak[2];
//  Скрипт, вызвавший пиковую нагрузку
$peak_script = $peak[3];

//  теперь запишем эти данные в БД, для последующей обработки данных.
$sql = new base();
$query = "INSERT INTO log_peak_sql_query SET peak_date_year='"
        .$peak_data_file[3]."', peak_date_month='".$peak_data_file[2]
        ."', peak_date_day='".$peak_data_file[1]."', peak_time='"
        .$peak_data_file[4]."', peak_exec=".$peak_exec.", peak_query='"
        .$sql->escape_string($peak_query)."', peak_script='"
        .$sql->escape_string($peak_script)."'";
$result = $sql->query($query);
if (!$result){
    echo $sql->errno . '<br>';
    echo $sql->error;
    exit ();
}
else {
    echo '<br>Данные пиковой нагрузки успешно записаны в БД.<br>';
}

//  теперь читаем содержимое каталога и удаляем все txt записи.
$folder_list = glob(CACHE.'*.txt');
//  перебираем содержимое каталога и удаляем поименно :)
for ($i=0; $i<count($folder_list); $i++){
    unlink($folder_list[$i]);
}

echo 'Скрипт записи в БД и очиски кэша выполнен успешно!';
?>


в принципе во 2-м пункте все сделано для записи ы БД и для вывода на экран результатов работы скрипта.
При необходимости можно лишнее убрать иили настроить запись не в БД, а в файл, лежащий вне пределов доступа из web. (это уже скорее для тех, кто будет использовать эту заготовку).
а так вот, на локали работает, осталось проверить только на боевом сервере...

Добавлено спустя 16 минут 52 секунды:
Да чуть не забыл, вот что у меня в классе my записано:
Код: Выделить всё
class my {
    protected $my_month_cut_eng = array(
                'Jan',
                'Feb',
                'Mar',
                'Apr',
                'May',
                'Jun',
                'Jul',
                'Aug',
                'Sep',
                'Oct',
                'Nov',
                'Dec');
    public function replaceEngCutMonthToNum($month){
        $my_month = $this->my_month_cut_eng;
   for ($i=0; $i<12; $i++) {
      if (strtolower($my_month[$i])==strtolower($month)) {
         $i++;
         return $i;
      }
   }
    }
}
Ответить


рррр, забыл проверку на наличие файла сделать (файла пиковой нагрузки), что бы скрипт не лопатил в пустую...

Код: Выделить всё
//  если файл был успешно открыт, то закроем файл, так как все уже прочитано.
if ($file)   {
      fclose($file);
}
else {
exit();
}


ЗЫ. как всегда правильный код либо снится, либо приходит за чашечкой чая (600 мл)...
Ответить


Вопрос по теме

Доброго времени суток а можно примерчик с подключение и инициализацией класса и еще можно только кешировать mysql_fetch_assoc или можно кешировать mysql_fetch_object ?
Ответить


new_forward писал(а): а можно примерчик с подключение и инициализацией класса

Можно. Примерчик есть на странице топика. Там сначала как мы класс создаём под конкретный запрос, а потом - как обращаемся к нему.

new_forward писал(а):можно только кешировать mysql_fetch_assoc или можно кешировать mysql_fetch_object ?

Да. mysql_fetch_object я не стал вставлять в скрипт. Мне это показалось лишним усложнением.
Ответить


Если два запроса рядом?

Доброго времени суток!
Делаю первый запрос вот так:

$query_u="select * FROM pro_user WHERE login = '$user_log'";
$cache=new MySQLCache($query_u, 900);
$result_u=mysql_query($query_u);
$row_u=$cache->fetch_assoc();

Второй нужно вот так делать?

$query_m="select * FROM bm60_mails WHERE user = '".$user_log."@mixmir.net' AND gelesen = 'no' AND typ = 'in' AND trashed = 'no'";
$cache2=new MySQLCache($query_u2, 900);
$result_u2=mysql_query($query_u2);
$row_u2=count($cache2->fetch_assoc());

Чтоб получить количество записей...
Ответить


Всё перепутали.

$query_u="select * FROM pro_user WHERE login = '$user_log'";
$cache=new MySQLCache($query_u, 900);
$result_u=mysql_query($query_u);
$row_u=$cache->fetch_assoc();

$query_m="select * FROM bm60_mails WHERE user = '".$user_log."@mixmir.net' AND gelesen = 'no' AND typ = 'in' AND trashed = 'no'";
$cache2=new MySQLCache($query_u2, 900);
$result_u2=mysql_query($query_u2);
$row_u2=count($cache2->fetch_assoc());

$row_u2 = $cache2->num_rows();

А вообще, для получения количества не обязательно тянуть все строки. MySQL может сам посчитать строки, если нужно только это:

Код: Выделить всё
$query_m = "SELECT COUNT(*) FROM `bm60_mails` WHERE user = '" . $user_log . "@mixmir.net' AND gelesen = 'no' AND typ = 'in' AND trashed = 'no'";
$cache2 = new MySQLCache($query_u2, 900);
$row_u2 = $cache2->fetch_row();
$count = $row_u2[0]
Ответить


Спасибо большое что разъяснили что к чему...
Ответить


Вопрос

Добрый день, пытаюсь понять будет ли полезно установка этого скрипта на мои сайты (Джумла). Сейчас на них стоит плгин для кеширования зпросов к базе (вот этот http://joomla-school.com/optimizacziya/ ... annyx.html)

Вы не могли бы сказать, если не трудно - это по сути одно и тоже или Ваш скрипт чем-то отличается?
Ответить


Dram, действительно, это примерно одно и то же.
Вообще, если у вы используете стандартный движок и к нему есть стандартные плагины, то лучше работать с ними.
Мой скрипт больше подходит тем, кто использует самописный движок, т.к. при использовании моего скрипта нужно будет переписывать все вызовы БД. Перелопачивать стандартный движок было бы не рационально.
Ответить


Пред.

Вернуться в PHP-скрипты



Кто сейчас на сайте

Зарегистрированные пользователи: Bing [Bot]