Проектирование базы данных SQL - таблицы кеша? - PullRequest
1 голос
/ 22 сентября 2010

Какова общая / лучшая практика для проектирования баз данных, когда речь идет об улучшении производительности по count(1) запросам?( В настоящее время я использую SQLite )

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

например:

SELECT count(1) from actions where type='3' and area='5' and employee='2533';

Но когда я начинаю получать запросы к нескольким таблицам, все становится слишком медленным (> 1 секунда).

SELECT count(1) 
  from
  (SELECT SID from actions 
      where type='3' and employee='2533' 
   INTERSECT 
     SELECT SID from transactions where currency='USD') x;

Как мне кэшировать свои результаты?Что такое хороший дизайн?Моя естественная реакция - добавить таблицу исключительно для хранения строк кэшированных результатов на сотрудника?

1 Ответ

1 голос
/ 22 сентября 2010

Редактировать

Шаблоны проектирования, такие как Command Query Responsibility Segregation (CQRS) , специально направлены на улучшение read side производительности доступа к данным, часто в распределенных системах и намасштаба предприятия.

  • Команды выдаются для указания «транзакций» или «изменения / обновления» данных
  • Когда система обрабатывает эти команды (например, путем обновления таблиц базы данных), новаясостояние затронутых объектов является «широковещательным»
  • Системы, которые заинтересованы (например, пользовательский интерфейс или запрашиваемый API REST), затем подпишутся на эти изменения данных, а затем «придадут» обновленные данные их конкретнымneeds
  • Эти обновленные данные затем кэшируются (часто называемые «хранилищем чтения»)

Другой шаблон, обычно связанный с CQRS, - это «Event Sourcing» , которыйсохраняет, а затем разрешает «воспроизведение» команд для различных вариантов использования.

Вышеприведенное может быть излишним для вашего сценария, но очень простой реализацией кэширования во внутреннем файле приложения.vel, может быть через Sqllite Trigger

При условии, что число операций чтения намного выше, чем при записи в таблицы actions или transactions,

  • Вы можете создать кеш-таблицы специально для «SID для действий по типу по сотруднику» и одну для «SID для транзакций по валюте», или даже объединить две (зависит от того, какие другие сценарии у вас есть для запросов)
  • Затем вам нужно будет обновлять эти таблицы кэша каждый раз, когда обновляются базовые таблицы action или transactions.Одним дешевым (и неприятным) способом было бы предоставить триггеры INSERT, UPDATE и DELETE для таблиц action и transactions, которые затем обновили бы соответствующие таблицы кеша.
  • Ваш запросИнтерфейс теперь будет в основном взаимодействовать с таблицами кеша, используя «производные» данные (такие как счетчики).
  • Тем не менее, вам все равно может потребоваться обработать сценарии пропадания кеша, такие как начальное «начальное число» этихкэшированные таблицы или если таблицы кэширования необходимо регенерировать.

В дополнение к локальной реляционной базе данных, такой как SqlLite, базы данных NoSql, такие как MongoDb, Cassandra and Redis, часто используются в качестве альтернативы для чтения бокового кэширования всреды с интенсивным чтением (в зависимости от типа и формата данных, которые необходимо кэшировать).Однако вам нужно будет обработать альтернативу для синхронизации данных из вашей базы данных 'master' (например, SQLLite) с этими хранилищами чтения кэша - триггеры, очевидно, здесь не будут обрезаться.

Оригинальный ответ

Если вы на 100% уверены, что всегда повторяете один и тот же запрос для одного и того же клиента, сохраняете результат.

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

INTERSECT с запросом

SELECT SID from transactions where currency='USD'

Может быть проблематично, если имеется большое количество записей транзакций с долларами США.

Возможно, вы могли бы заменить это объединением?

SELECT count(1) from 
(
    SELECT t.[SID] 
    from
        transactions as t
        inner join
        (
            SELECT SID from actions where type='3' and employee='2533'
        ) as a
        on t.SID = a.SID
    where t.currency= 'USD'
) as a

Однако вы можете просто проверить свои индексы:

Для

  • SELECT count (1) из действий, где type = '3' и area ='5' и employee = '2533'
  • ВЫБРАТЬ SID из действий, где type = '3' и employee = '2533'

Индекс Actions(Employee, Type) или Actions(Employee, Type, Area)будет иметь смысл (при условии, что сотрудник имеет наивысшую избирательность иПримечание о селективности типа и области).

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

А для объединения выше вам нужен индекс на Transactions(SID, Currency)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...