Каков хороший способ денормализовать базу данных mysql?

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

Есть много запросов, и большинство из них были максимально оптимизированы, чтобы снизить нагрузку на сервер и увеличить скорость. Думаю, пора начать хранить копию данных в денормализованном формате.

Есть идеи по поводу подхода? Должен ли я начать с пары моих наихудших вопросов и перейти к ним?

Ответов (8)

Решение

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

http://dev.mysql.com/doc/refman/5.0/en/explain.html

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

Вот сайт, который, как я нашел, затрагивает эту тему:

http://www.meansandends.com/mysql-data-warehouse/?link_body%2Fbody=%7Bincl%3AAggregation%7D

Вот простой метод, который вы можете использовать, чтобы упростить денормализацию запросов, если вы просто выполняете несколько операций за раз (и я не заменяю ваши таблицы OLTP, а просто создаю новую для целей отчетности). Допустим, у вас есть этот запрос в вашем приложении:

select a.name, b.address from tbla a 
join tblb b on b.fk_a_id = a.id where a.id=1

Вы можете создать денормализованную таблицу и заполнить ее почти тем же запросом:

create table tbl_ab (a_id, a_name, b_address); 
-- (types elided)

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

insert tbl_ab select a.id, a.name, b.address from tbla a
join tblb b on b.fk_a_id = a.id 
-- no where clause because you want everything

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

select a_name as name, b_address as address 
from tbl_ab where a_id = 1;

Для огромных запросов это может сэкономить много времени и прояснить, откуда пришли данные, и вы можете повторно использовать запросы, которые у вас уже есть.

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

[Еще одно изменение] Не забывайте, что новые таблицы, которые вы создаете, тоже нужно индексировать! Хорошая часть состоит в том, что вы можете индексировать, сколько душе угодно, и не беспокоиться о конфликте блокировки обновления, поскольку помимо вашей массовой вставки таблица будет видеть только выбранные.

Что касается MySQL, мне нравится этот доклад: Real World Web: Performance & Scalability, MySQL Edition . В нем содержится много разных советов по увеличению скорости работы MySQL.

Я знаю, что это немного косвенно, но пробовали ли вы посмотреть, есть ли еще индексы, которые вы можете добавить?

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

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

В любом случае, если это то, что вы еще не рассматривали, это очень помогло мне ... но если вы уже прошли этот путь, то я думаю, это не то, что вы ищете.

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

MySQL 5 поддерживает представления , которые могут быть полезны в этом сценарии. Похоже, вы уже проделали большую оптимизацию, но если нет, вы можете использовать синтаксис MySQL EXPLAIN, чтобы увидеть, какие индексы фактически используются и что замедляет ваши запросы.

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

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

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

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

Чтобы дать представление о производительности с хорошими индексами (включая многочисленные составные индексы), я могу выполнять запросы, объединяющие 3 таблицы в нашей базе данных, и в большинстве случаев получать почти мгновенные результаты. Для более сложных отчетов большинство запросов выполняется менее чем за 10 секунд. Эти 3 таблицы содержат 33 миллиона, 110 миллионов и 140 миллионов строк соответственно. Обратите внимание, что мы также немного нормализовали их, чтобы ускорить наш самый распространенный запрос к базе данных.

Дополнительная информация о ваших таблицах и типах запросов отчетов может помочь в дальнейших предложениях.

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

Мы обнаружили, что этот подход легко реализовать, поскольку он не сломал ничего из того, что уже работало - это просто дополнительные вставки в базу данных в определенные моменты.

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