В общем сделал, как подсказывали.
1) Получаю
id всех карт.
2) Для каждой карты строю список запросом, который приведен в вопросе.
3) Кэширую полученные данные.
Кэширование пришлось сделать извращенное, т.к. сервер у меня работает на виртуальном хостинге и
Memcached не доступен.
Первое, что пришло в голову — это сделать
memory таблицу и хранить закешированные данные в ней, данные будут хранится в формате json. После тестов, оказалось, что для хранения всех(текстовых) данных, недостаточно 65536 байт. В итоге, пришлось сделать обычную таблицу, и хранить в ней с типом данных
blob.
Кому интересно, вот код:
function CacheGet($key)
{
$query = "SELECT ";
$query .= " data ";
$query .= "FROM ";
$query .= " CacheTable ";
$query .= "WHERE ";
$query .= " name = \"".$key."\" ";
$query .= " AND (expire > ".time()." OR locked = 1)";
$result = mysql_query($query);
if ($result == false)
{
return false;
}
else
{
$data = mysql_fetch_array($result, MYSQL_ASSOC);
return $data[data];
}
}
// lock cache while one process write new updated data
function CacheLock($key)
{
$query = "INSERT INTO CacheTable (name, locked) ";
$query .= " VALUES(\"".$key."\", 1) ";
$query .= "ON DUPLICATE KEY UPDATE ";
$query .= " name = VALUES(name),";
$query .= " locked = VALUES(locked)";
mysql_query($query);
}
function CacheSet($key, $data, $expire)
{
$query = "INSERT INTO CacheTable (name, data, expire, locked) ";
$query .= " VALUES(\"".$key."\", \"".mysql_real_escape_string($data)."\", ".(time() + $expire).", 0) ";
$query .= "ON DUPLICATE KEY UPDATE ";
$query .= " name = VALUES(name), ";
$query .= " data = VALUES(data), ";
$query .= " expire = VALUES(expire), ";
$query .= " locked = VALUES(locked)";
mysql_query($query);
}
Теперь при получении топа, если функция
CacheGet возвращает
false, то мы блокируем данные по этому ключу, чтобы другие пользователи тоже не начали записывать новые данные в кэш. А дальше, после записи обновленных данных, разблокируем данные по этому ключу.