Смарт (?) Кэш базы данных

Я видел несколько механизмов кэширования баз данных, все они довольно глупые (т. keep this query cached for X minutes ) и требуют, чтобы вы вручную удалили весь репозиторий кеша после выполнения запроса INSERT / UPDATE / DELETE .

Около 2 или 3 лет назад я разработал альтернативную систему кэширования БД для проекта, над которым я работал, идея заключалась в основном в использовании регулярных выражений для поиска таблиц, участвующих в конкретном запросе SQL:

 $query_patterns = array ( 'INSERT' => '/INTO\s+(\w+)\s+/i', 'SELECT' => '/FROM\s+((?:[\w]|,\s*)+)(?:\s+(?:[LEFT|RIGHT|OUTER|INNER|NATURAL|CROSS]\s*)*JOIN\s+((?:[\w]|,\s*)+)\s*)*/i', 'UPDATE' => '/UPDATE\s+(\w+)\s+SET/i', 'DELETE' => '/FROM\s+((?:[\w]|,\s*)+)/i', 'REPLACE' => '/INTO\s+(\w+)\s+/i', 'TRUNCATE' => '/TRUNCATE\s+(\w+)/i', 'LOAD' => '/INTO\s+TABLE\s+(\w+)/i', ); 

Я знаю, что эти регулярные выражения, вероятно, имеют некоторые недостатки (мои навыки регулярного выражения были довольно зелеными) и, очевидно, не соответствуют вложенным запросам, но поскольку я никогда не использую их, это не проблема для меня.

Во всяком случае, после поиска задействованных таблиц я в алфавитном порядке сортировал их и создавал новую папку в репозитории кеша со следующим соглашением об именах:

 +table_a+table_b+table_c+table_...+ 

В случае запроса SELECT я бы извлек результаты из базы данных, serialize() и сохранил их в соответствующей папке кеша, поэтому, например, результаты следующего запроса:

 SELECT `table_a`.`title`, `table_b`.`description` FROM `table_a`, `table_b` WHERE `table_a`.`id` <= 10 ORDER BY `table_a`.`id` ASC; 

Будет храниться в:

 /cache/+table_a+table_b+/079138e64d88039ab9cb2eab3b6bdb7b.md5 

MD5 является самим запросом. После последующего запроса SELECT результаты будут тривиальны для извлечения.

В случае любого другого типа запроса на запись ( INSERT , REPLACE , UPDATE , DELETE и т. Д.), Я бы glob() все папки, у которых были +matched_table(s)+ в их имени, +matched_table(s)+ все содержимое файла. Таким образом, нет необходимости удалять весь кеш, только кеш, используемый соответствующими и связанными с ним таблицами.

Система работала довольно хорошо, и разница в производительности была видна – хотя в проекте было много запросов на чтение, чем на запросы записи. С тех пор я начал использовать транзакции, FK CASCADE UPDATES / DELETES и никогда не успевал совершенствовать систему, чтобы она работала с этими функциями.

Я использовал MySQL Query Cache в прошлом, но я должен сказать, что производительность даже не сравнивается.

Мне интересно: я единственный, кто видит красоту в этой системе? Есть ли какие-то узкие места, о которых я не знаю? Почему в таких популярных фреймворках, как CodeIgniter и Kohana (я не знаю Zend Framework ), есть такие рудиментарные системы кэширования БД?

Что еще более важно, вы видите это как функцию, которую стоит преследовать? Если да, есть ли что-нибудь, что я мог бы сделать / использовать, чтобы сделать это еще быстрее (мои основные проблемы – дисковый ввод-вывод и (де) сериализация результатов запроса)?

Я ценю все входные данные, спасибо.

Solutions Collecting From Web of "Смарт (?) Кэш базы данных"

Я вижу красоту в этом решении, однако, я считаю, что он работает только для очень специфического набора приложений. Сценарии, в которых это не применимо, включают:

  • Базы данных, которые используют каскадные удаления / обновления или любые триггеры. Например, ваш DELETE в таблицу A может вызвать DELETE из таблицы B. Регулярное выражение никогда не поймает это.

  • Доступ к базе данных из точек, которые не проходят через схему аннулирования кэша, например скрипты crontab и т. Д. Если вы когда-либо решили внедрить репликацию на разных машинах (ввести ведомые только для чтения), это может также повредить кеш (поскольку он не проходит кэш-аннулирование и т. д.)

Даже если эти сценарии нереалистичны для вашего случая, они все еще отвечают на вопрос, почему инфраструктура не реализует этот вид кеша.

Что касается того, стоит ли это делать, все зависит от вашего приложения. Может быть, вы хотите предоставить дополнительную информацию?

Решение, как вы его описываете, подвержено риску возникновения проблем с параллелизмом. Когда вы получаете сотни запросов в секунду, вы должны столкнуться с случаем, когда выполняется оператор UPDATE, но прежде чем вы сможете очистить кеш, SELECT читает его и получает устаревшие данные. Кроме того, вы можете столкнуться с проблемами, когда несколько UPDATE попадают в один и тот же набор строк за короткий промежуток времени.

В более широком смысле наилучшей практикой кэширования является кэширование самых больших объектов. Например, вместо того, чтобы иметь кучу «связанных с пользователем» строк, кэшированных по всему месту, лучше просто кэшировать сам «пользовательский» объект.

Еще лучше, если вы можете кэшировать целые страницы (например, вы показываете одну и ту же домашнюю страницу для всех, страница профиля похожа на почти всех и т. Д.), Это еще лучше. Одна выборка кеша для целой страницы с предварительным рендерингом значительно превосходит десятки кеш-фреймов для кешей уровня / уровня запросов, за которыми следует повторная разметка страницы.

Короче говоря: профиль. Если вы потратите время на выполнение некоторых измерений, вы, скорее всего, обнаружите, что кеширование больших объектов или даже страниц, а не небольших запросов, используемых для создания этих вещей, – огромный выигрыш в производительности.

В то время как я вижу красоту в этом – особенно для сред, где ресурсы ограничены и не могут быть легко расширены, например, на совместном хостинге – я лично буду бояться осложнений в будущем: что, если кто-то, недавно нанятый и не осознающий механизм кеширования, начинает использовать вложенные запросы? Что делать, если какая-либо внешняя служба начинает обновлять таблицу, а кеш не замечает?

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

Я подозреваю, что регулярные выражения могут не предоставлять для каждого случая – конечно, они, похоже, не имеют отношения к сценарию смешивания имен базовых таблиц и самих таблиц. например, рассмотреть

update stats.measures set amount = 50 где id = 1;

а также

статистика использования; количество установленных мер обновления = 50, где id = 1;

Тогда есть PL / SQL.

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

(как небольшая точка), было бы проще просто проверить время модификации файлов данных, чтобы определить, остается ли кешированная версия запроса в определенном наборе таблиц, а не пытаться определить, используется ли управление кешем механизм обнаружил обновление – это, безусловно, было бы намного более надежным)

Отступив немного, реализация этого с нуля с использованием надежной архитектуры означала бы, что все запросы должны быть перехвачены механизмом управления. Механизму управления, вероятно, потребуется более сложный синтаксический анализатор запросов. Разумеется, для всех экземпляров механизма управления требуется общий субстрат сторожевого диска. Это, вероятно, нуждается в понимании словаря данных – все, что уже реализовано самой базой данных.

Вы заявляете, что «я использовал MySQL Query Cache в прошлом, но я должен сказать, что производительность даже не сравнивается».

Я нахожу это довольно странным. Конечно, имея дело с большими наборами результатов из запросов, мой опыт заключается в том, что загрузка данных в кучу из базы данных происходит намного быстрее, чем неэтериализация больших массивов – хотя большие результирующие наборы довольно нетипичны для веб-приложений.

Когда я попытался ускорить доступ к базе данных (после исправления всего остального, конечно), я пошел по пути репликации и разбиения данных на несколько экземпляров СУБД.

C.

Это связано с проблемой разделения сеансов при работе с несколькими базами данных в конфигурации «ведущий-ведомый». В принципе, аналогичный набор регулярных выражений используется для определения того, какие таблицы (или даже какие строки) считываются или записываются в. Система отслеживает, какие таблицы были записаны и когда, и когда приступает к чтению в одну из этих таблиц, она направляется мастеру. Если запрос читается из таблицы, данные которой не обязательно должны быть точными, то она направляется к ведомому. Как правило, информация действительно должна быть актуальной, когда пользователь сам меняет себя (т. Е. Редактирует профиль пользователя).

Они говорят об этом в битве в книге O'Reilly High Performance MySQL. Я использовал его совсем немного, когда разрабатывал систему для обработки разделов сеансов в тот же день.

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

Это, конечно, хорошо, но я не уверен, достаточно ли он достаточно тонкий, чтобы иметь реальное значение. Вы по-прежнему будете нести большое количество кэшей, которые действительно не нужны (потому что обновление было на столе, но на разных строках).

Кроме того, даже эта «простая» схема основана на возможности обнаруживать соответствующие таблицы, просматривая строку запроса SQL. Это может быть сложно сделать в общем случае из-за представлений, псевдонимов таблиц и нескольких каталогов.

Очень сложно автоматически (и эффективно) определить, должен ли кеш быть недействительным. Из-за этого вы можете использовать очень простую схему (например, недействительность для каждого обновления или для таблицы, как в вашей системе, которая не работает слишком хорошо, когда есть много обновлений), или очень ручной кеш для конкретное приложение с глубокими перехватами в логике запросов (возможно, трудно писать и трудно поддерживать), или принять, что кеш может содержать устаревшие данные и периодически обновлять их.