У меня есть таблица "объектов" с 1 миллионом строк и "пользовательская" таблица с 20 000 строк. Когда я выбираю из таблицы "объектов", я делаю соединение на "пользовательской" таблице (объекты user_id = user.id), так, чтобы я мог захватить "имя пользователя" от пользовательской таблицы.
Я рассматриваю добавление столбца имени пользователя к таблице объектов и удалению соединения. Я могу ожидать достойное увеличение производительности с этого? Это уже довольно быстро, но было бы хорошо уменьшить мою загрузку (который довольно высок).
Оборотная сторона - то, что, если пользователь изменяет их имя пользователя, объекты все еще отразят свое старое имя пользователя, но это хорошо со мной, если я могу ожидать достойное увеличение производительности.
Я спрашиваю stackoverflow, потому что сравнительные тесты не говорят мне слишком много. Оба запроса заканчиваются очень быстро. Независимо, я задаюсь вопросом, если удаление соединения осветило бы нагрузку на базу данных до любой существенной степени.
Запрос в качестве примера с соединением:
ВЫБРАТЬ Item
.id
, Item
.submitter_id
, Item
.source_image
, Item
.cached_image
, Item
.source_title
, Item
.source_url
, Item
.width
, Item
.height
, Item
.status
, Item
.popular
, Item
.made_popular
, Item
.fave_count
, Item
.tags
, Item
.user_art
, Item
.nudity
, Item
.created
, Item
.modified
, Item
.removed
, Item
.nofront
, Item
.test
, Item
.recs
, Item
.recs_data
, User
.id
, User
.username
, User
.password
, User
.email
, User
.fullname
, User
.profileurl
, User
.homepage
, User
.bio
, User
.location
, User
.avatar
, User
.ff_user
, User
.ff_key
, User
.ff_last_faveid
, User
.twitter_user
, User
.twitter_pass
, User
.emailalerts
, User
.showunsafe
, User
.view
, User
.fb_uid
, User
.fb_session
, User
.fb_avatar
, User
.twitter_uid
, User
.twitter_data
, User
.twitter_autopost
, User
.uri
, User
.created
, User
.modified
ОТ items
AS Item
ОСТАВЛЕННОЕ СОЕДИНЕНИЕ users
AS User
НА (Item
.submitter_id
= User
.id
) ГДЕ Item
.nofront
! = 1 И Item
.removed
! = 1 И Item
.made_popular
не является ПУСТЫМ И нагота! = 1 ORDER BY Item
.made_popular
ПРЕДЕЛ DESC 1040, 290;
Запрос в качестве примера без соединения:
ВЫБРАТЬ Item
.id
, Item
.submitter_id
, Item
.source_image
, Item
.cached_image
, Item
.source_title
, Item
.source_url
, Item
.width
, Item
.height
, Item
.status
, Item
.popular
, Item
.made_popular
, Item
.fave_count
, Item
.tags
, Item
.user_art
, Item
.nudity
, Item
.created
, Item
.modified
, Item
.removed
, Item
.nofront
, Item
.test
, Item
.recs
, Item
.recs_data
ОТ items
AS Item
ГДЕ Item
.nofront
! = 1 И Item
.removed
! = 1 И Item
.made_popular
не является ПУСТЫМ И нагота! = 1 ORDER BY Item
.made_popular
ПРЕДЕЛ DESC 1040, 290;
Правильный ответ - измерить его в целевой среде , чтобы увидеть, имеет ли это значение. Затем проведите анализ затрат и выгод, чтобы понять, стоит ли оно того.
Стоимость - это дополнительное хранилище и возможность рассинхронизации данных (но см. Ниже, как это уменьшить). Преимущество заключается в увеличении скорости или уменьшении нагрузки.
Схемы базы данных - это , а не операции «установить и забыть», они должны периодически настраиваться по мере изменения базовых данных. Это то, за что платят администраторам баз данных - постоянный мониторинг и настройку.
В любом случае дублирование столбца можно довольно легко контролировать в приличной СУБД с помощью триггеров. Под этим я имею в виду размещение триггера вставки / обновления в таблице пользователей, чтобы, если пользователь изменяет свое имя пользователя, оно также изменялось в таблице элементов (и, возможно, наоборот).
Я не могу комментировать, соответствует ли MySQL моему определению достойной СУБД - я сам являюсь специалистом по DB2. Но возврат из третьей нормальной формы - это испытанный и проверенный метод выжать все до последней капли производительности из баз данных и, если вы понимаете последствия, вполне приемлем. Очень немногие люди жалуются на то, что их базы данных занимают слишком много места на диске. Многие жалуются на то, как медленно выполняются их запросы.
Просто имейте в виду, что реверсия - это то, что вы делаете , если и когда у вас есть проблемы с производительностью. Это не то, что следует делать только потому, что вы думаете, что это может снизить нагрузку.Если нагрузка (или затраченное время) на самом деле не является проблемой, часть выгоды вашего анализа затрат / выгод равна нулю, поэтому любой разумный счетчик bean скажет вам, что это означает «без изменений».
Основываясь на ваших добавленных вопросах, у меня есть пара замечаний:
нагота
. Скажите, пожалуйста, как мне получить доступ к этой базе данных: -) User
, вы не должны получать все эти лишние данные в первом запросе. Возможно, то же самое и с предметом Item
- получите только то, что вам нужно. WHERE
- это также может повлечь за собой комбинированные индексы (с несколькими столбцами). То, что будет индексироваться, зависит от ваших запросов, но каждый столбец, используемый в предложениях WHERE
, является хорошим началом для анализа. RemovedItems
), чтобы минимизировать размер элементов
и ускорить запросы. Но имейте в виду, что это полезно только в том случае, если вам редко нужно искать ромовированные элементы, поскольку это усложнит эти запросы (заставляя их искать в двух таблицах вместо одной). Опять же, это вопрос затрат и выгод. Один миллион строк - это не такая уж большая таблица (по крайней мере, в моем мире). Вы увидите значительное увеличение производительности только в том случае, если вам не хватало индекса для items.user_id
или user.id
, или если вы используете дрянную базу данных. В противном случае производительность существенно не улучшится.
JOINS всегда занимают больше ресурсов, чем простые операторы SELECT. Так что да, удаление JOIN должно повысить производительность.
У меня есть таблица "items" с 1 миллионом строк и таблица "users" с 20 000 строк.
То есть, независимо от того, JOIN
или денормализация, вы все равно передадите по проводам примерно 1M/20k = в 50 раз больше пользовательской
информации, чем это строго необходимо. Кодирование, передача и последующее декодирование данных увеличивают нагрузку.
Я рассматриваю возможность добавления столбца имени пользователя в таблицу items и удаления объединения.
Зачем вы тогда в своем оригинальном JOIN
передаете всю эту другую (потенциально объемную) информацию (такую как User.profileurl
, User.homepage
и т.д.), если вам нужно только имя пользователя? Помните, что для столбцов User
вы передаете в среднем 50 копий каждого бита информации. Не рассматривали ли вы возможность радикально сократить столбцы, из которых вы ВЫБИРАЕТЕ
в JOIN
(как из User
, так и из Item
таблиц?)
Я спрашиваю на stackoverflow, потому что эталоны не говорят мне слишком многого. Оба запроса завершаются очень быстро. Независимо от этого, мне интересно, снизит ли удаление join нагрузку на базу данных в сколько-нибудь значительной степени.
На первом этапе удаление столбцов, которые вы не собираетесь использовать, может снизить нагрузку, поскольку меньше данных нужно кодировать, передавать (от сервера к клиентскому приложению), а затем декодировать.
На втором этапе позвольте мне начать с собственного вопроса: действительно ли вам нужен весь миллион строк за один раз? Если нет, например, если вы ориентируетесь на пользовательский интерфейс и разбиваете их на страницы (используя OFFSET ... LIMIT ...
), то вас не обязательно будет заботить 50-кратное User
дублирование информации (если только LIMIT
не достигает десятков тысяч. В противном случае вы можете захотеть измерить преимущество устранения 50-кратного дублирования, сначала ВЫБРАВ
вписав только User.id
и User. username
в память приложения (20k пар, в хэш-таблицу/карту), затем SELECT
ing only Item
rows (1M итераций), каждый раз разрешая на уровне приложения Item.user_id
по хэш-таблице/карте.
Конечно, всегда используйте EXPLAIN
, чтобы убедиться, что нужные индексы существуют и используются, когда индекс должен использоваться, и запускайте ANALYZE TABLE
после того, как любая из ваших таблиц вырастет с нескольких сотен строк до тысяч или миллионов.
Я предлагаю вам оставить это так, чтобы сохранить нормализованную таблицу. Я думаю, что не стоит помещать имена пользователей в таблицу элементов, поскольку это сделает данные избыточными. Вы пробовали переиндексировать свою таблицу?