[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: MySQL и memcached
Cookson
Здравствуйте.

Некоторое время назад начал изучать memcached. Решил проверить скорость выборки из mysql и вытягивания данных из memcached.

Была использована таблица из 3 полей и 10,000 записей. Задача: вывести все данные таблицы из MySQL напрямую и через memcached

1) MySQL:
Делалось

$q=mysql_query('select * from table test');
while ($res=mysql_fetch_row($q)) {
//вывести запись
}

и все записи выводились в браузер
Время выполнения: 10-15 миллисекунд

2) memcached:
Из базы инфа копировалась в мемкэш и выводилась в браузер из кэша.
Результат удручаюший: учитывая только время, которое инфа выводилась из кэша, на процедуру затрачивалось примерно 350 миллисекунд.

3) На всякий случай попробовал такое извращение: каждый ряд получать новым запросом. Средний результат: 550 миллисекунд, всего лишь в полтора раза медленне, чем из кэша!

Итак, вопросы.
Всё правильно, так и должно быть? Похоже, я чего-то недопонимаю.

Как может информация из кэша, из памяти, читаться быстрее, чем из базы, с жёсткого диска? Причём, во столько раз быстрее.

Неужели преимущества мемкэша только в таких мелких выборках, как в третьем примере, ну и в масштабируемости на несколько серверов? Получается, в относительно небольших базах на несколько десятков мегабайт и под миллион записей он совсем не нужен? Когда тогда его стоит использовать?



Спустя 14 минут, 40 секунд (2.05.2010 - 21:17) kirik написал(а):
Во-первых у mysql есть свой кэш и держится он тоже в памяти (как и мемкэш). Чтобы сделать запрос без кэширования, нужно добавить SQL_NO_CACHE.
Во-вторых запрос select * from table test - это простой запрос, без условий, джоинов и прочих сложностей, тоесть можно предположить что он не будет уступать по скорости тому же мемкэшу.
Скажу лишь что сравнивать скорость систем разных типов и предназначений не вежливо =) MySQL - это сервер баз данных, а memcache - это сервер кэша в памяти.

Запрос с 3-мя условиями по индексам и с джоином 2х больших таблиц в условиях нагрузки выполняется > 10 секунд! Без нагрузки, на локалхосте, выборка происходит моментально. Вот тут и нужен мемкэш.

Спустя 51 минута, 38 секунд (2.05.2010 - 22:09) Cookson написал(а):
Спасибо.

Спустя 12 часов, 44 минуты, 49 секунд (3.05.2010 - 10:54) vasa_c написал(а):
Есть предположение, что вы хреново организовали тесты.

Спустя 1 минута, 12 секунд (3.05.2010 - 10:55) vasa_c написал(а):
Цитата
Во-вторых запрос select * from table test - это простой запрос, без условий, джоинов и прочих сложностей

Если бы простые запросы в mysql не уступали бы простым запросам в memcached (в котором только они и возможны), memcached не был бы нужен.

Спустя 8 часов, 28 минут, 25 секунд (3.05.2010 - 19:23) Cookson написал(а):
Цитата
Есть предположение, что вы хреново организовали тесты.


Да там организовывать-то нечего. Вот этот код доставал инфу из кэша:


for ($i=0;$i<10000;$i++) {
echo $cache->get('cache'.$i);
}


Само собой, перед этим были засетены cache[1..10000] в мемкэше.

Повторюсь, время, которое инфа забивалась в кэш, я не учитывал.

И, всё-таки: как могут в принципе 10000 значений из кэша доставаться быстрее, чем то же количество записей из MySQL, включая выборку запросом и вывод всех записей? Хорошо, пусть MySQL тоже кэширует выдачу, я об этом слышал и раньше. Но что это у майэскуэля за кэш такой, который работает в сорок раз быстрее, чем прямое вытягивание значений мемкэшем из памяти?

Спустя 43 минуты, 56 секунд (3.05.2010 - 20:07) vasa_c написал(а):
Один "SELECT *" и десять тысяч запросов на одельные ключи это совершенно разные вещи.
Попробуйте 10 000 раз сделать SELECT одной строки.
Здесь только сетевой обмен столько выест, что даже будь мемкэш бесконечно быстрым это бы не спасло.
У мемкэша, кстати, для этого есть multi-get

Спустя 44 минуты, 23 секунды (3.05.2010 - 20:52) kirik написал(а):
Цитата (vasa_c @ 3.05.2010 - 12:07)
Попробуйте 10 000 раз сделать SELECT одной строки.

1-й запрос выберет данные в кэш, все остальное будет идти уже из кэша. Так что тут и мемкэш и mysql почти в равных условиях. Если взять сложный запрос, когда mysql не может кэшировать, тут конечно встречается затуп.. Я собсно вот о чем smile.gif

Спустя 18 минут, 5 секунд (3.05.2010 - 21:10) vasa_c написал(а):
под одной я не имел ввиду "одной и той же".

Спустя 7 дней, 10 минут, 48 секунд (10.05.2010 - 21:21) Cookson написал(а):
Цитата (vasa_c @ 3.05.2010 - 12:07)
Попробуйте 10 000 раз сделать SELECT одной строки.

Это я и сделал в третьем тесте, читайте в верхем посте.

Спустя 1 день, 22 часа, 59 минут, 43 секунды (12.05.2010 - 20:20) vasa_c написал(а):
Ubuntu 9.10

-- Таблица в MySQL, эмулирующая key-value связки
DROP TABLE IF EXISTS `mcdb`;
CREATE TABLE `mcdb` (
`key` CHAR(15) NOT NULL,
`value` VARCHAR(200) NOT NULL,
PRIMARY KEY (`key`)
) ENGINE=InnoDB;


Забиваем ключами:
<?php

header('Content-Type: text/plain');

define('KEYS_COUNT', 1000);

$data = array();
for ($i = 0; $i < KEYS_COUNT; $i++) {
$key = 'key_'.$i;
$value = md5($key);
$data[$key] = $value;
}


/*** MySQL ***/

mysql_connect('localhost', 'test', 'test');
mysql_select_db('test');

mysql_query('TRUNCATE `mcdb`');

$mtDB = microtime(1);
foreach ($data as $key => $value) {
$query = 'INSERT INTO `mcdb` SET `key`="'.mysql_real_escape_string($key).'", `value`="'.mysql_real_escape_string($value).'"';
mysql_query($query);
}
$mtDB = microtime(1) - $mtDB;

mysql_close();


/*** Memcached ***/

$mc = new Memcached();
$mc->addServer('localhost', 11211);
$mc->flush();

$mtMC = microtime(1);
foreach ($data as $key => $value) {
$mc->set($key, $value);
}
$mtMC = microtime(1) - $mtMC;


/*** Results ***/

$rMysql = (int)(KEYS_COUNT * 1.0 / $mtDB);
$rMc = (int)(KEYS_COUNT * 1.0 / $mtMC);

echo 'Mysql: '.$rMysql." set/sec\n";
echo 'Memcached: '.$rMc." set/sec\n";


Получаем ключи:
<?php

header('Content-Type: text/plain');

define('KEYS_COUNT', 100);

$keys = array();
for ($i = 0; $i < KEYS_COUNT; $i++) {
$key = 'key_'.$i;
$keys[] = $key;
}
shuffle($keys);


/*** MySQL ***/

mysql_connect('localhost', 'test', 'test');
mysql_select_db('test');

$dbResult = array();

$mtDB = microtime(1);
foreach ($keys as $key) {
$query = 'SELECT `value` FROM `mcdb` WHERE `key`="'.mysql_real_escape_string($key).'"';
$res = mysql_query($query);
$res = mysql_fetch_row($res);
$dbResult[$key] = $res[0];
}
$mtDB = microtime(1) - $mtDB;

mysql_close();

/*** Memcached ***/

$mc = new Memcached();
$mc->addServer('localhost', 11211);
$mc->flush();

$mcResult = array();

$mtMC = microtime(1);
foreach ($keys as $key) {
$mcResult = $mc->get($key);
}
$mtMC = microtime(1) - $mtMC;


/*** Results ***/

$rMysql = (int)(KEYS_COUNT * 1.0 / $mtDB);
$rMc = (int)(KEYS_COUNT * 1.0 / $mtMC);

echo 'Mysql: '.$rMysql." set/sec\n";
echo 'Memcached: '.$rMc." set/sec\n";


Mysql:     23 set/sec
Memcached: 7187 set/sec

Mysql: 4289 get/sec
Memcached: 9699 get/sec


На выборке мемкэш быстрее более чем вдвое, на вставке в несколько сотен раз.

При замене InnoDB на MyISAM вставка в базе ускоряется, но всё равно не дотягивает до мемкэша. Даже ENGINE=Memory медленнее.

Это всё для пустой базы и последовательных запросов. Когда начётся куча параллельных, блокировки и очереди, картина станет совсем другой.

Ну и это всё сферическая хренота в вакууме, не имеющая ничего общего с конкретными задачами и выбором под них инструментов.
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.