Я полагаю, что этот вопрос не касается конкретно MySQL - базы данных, которую я использую, - и о лучших практиках.
До сих пор мои проблемы можно было решить, создавая таблицы и запрашивая их (иногда присоединяясь здесь и там). Но есть кое-что, что я делаю, и это не правильно, и это вызывает у меня всякий раз, когда мне нужны денормализованные данные вместе с моими "общими" запросами.
Пример варианта использования
Чтобы я мог выразить себя лучше, давайте создадим поверхностный сценарий, где:
- a
user
может купить product
, генерируя purchase
(давайте проигнорируем тот факт, что purchase
может иметь только один product
);
- и нам нужно запросить
product
s с общим количеством раз, которое было purchase
d;
Чтобы решить наш сценарий использования, мы могли бы определить простую структуру , созданную следующим образом:
product
таблица:
user
таблица:
purchase
таблица:
purchase_id
[INT PK ]
product_id
[INT FK NOT NULL]
user_id
[INT FK NOT NULL]
Вот где это нехорошо : Когда нам нужно получить список product
с общим количеством покупок, я бы создал запрос:
# There are probably faster queries than this to reach the same output
SELECT
product.product_id,
(SELECT COUNT(*) FROM purchase
WHERE purchase.product_id = product.product_id)
FROM
product
Мое беспокойство вызвано тем, что я прочитал, что COUNT выполняет полное сканирование таблицы, и меня пугает выполнение вышеуказанного запроса при масштабировании до тысячи покупаемых продуктов - даже если я создал INDEX с product_id
FK на purchase
(MySQL делает это по умолчанию).
Возможные решения
Мои знания по реляционным базам данных довольно незначительны, поэтому я немного растерялся, сравнивая альтернативы (вероятные) для подобных проблем. Чтобы не сказать, что я не сделал свою домашнюю работу (поиск, прежде чем спрашивать), я нашел правдоподобным:
Создание транзакций:
Когда INSERT вводит новый purchase
, он всегда должен быть внутри транзакции, которая также обновляет таблицу product
с purchase.product_id
.
Возможные проблемы: человеческая ошибка. Кто-то может вручную вставить purchase
без выполнения транзакции и BAM - у нас несоответствие.
Создать триггеры:
Всякий раз, когда я вставляю, удаляю или обновляю какую-либо строку в некоторой конкретной таблице, я обновляю свою таблицу product
новым значением (bought_amount
). Таким образом, таблица станет:
product
таблица:
product_id
[INT PK]
bought_amount
[INT NOT NULL];
Возможные проблемы: дорогие триггеры? Есть ли способ, которым вставка завершается успешно, но триггер не сработает, оставляя меня в несогласованности?
Вопрос
Обновление определенных таблиц для хранения данных, которые постоянно изменяются, является ли правдоподобным подходом к СУБД? Является ли безопаснее и - в долгосрочной перспективе - выгоднее просто продолжать присоединяться и считать / суммировать другие вхождения?
Я нашел пару полезных вопросов / ответов по этому вопросу, но ни один из них не рассматривал эту тему в широкой перспективе.
Пожалуйста, примите во внимание мое незнание о РСУБД, так как я могу предложить бессмыслицу Возможные решения .