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

StackOverflow https://stackoverflow.com/questions/12890

  •  08-06-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

Я знаю о 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;

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

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

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

Другие советы

MySQL 5 поддерживает число просмотров, что может быть полезно в этом сценарии.Похоже, вы уже проделали большую оптимизацию, но если нет, вы можете использовать MySQL ОБЪЯСНИТЕ синтаксис, позволяющий увидеть, какие индексы на самом деле используются и что замедляет ваши запросы.

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

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

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

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

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

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

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

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

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

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

Что касается MySQL, то мне нравится этот разговор: Реальная Мировая Паутина:Производительность и масштабируемость, версия MySQL.Это содержит много различных советов по получению большей скорости от MySQL.

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top