Я работаю над мобильным веб-сайтом, популярность которого растет, и это приводит к росту некоторых ключевых таблиц базы данных, и мы начинаем видеть некоторые проблемы с производительностью при доступе к этим таблицам. Не являясь экспертами по базам данных (и не имея денег, чтобы нанять кого-либо на данном этапе), мы изо всех сил пытаемся понять, что вызывает проблемы с производительностью. Наши таблицы не настолько велики, поэтому SQL Server должен нормально их обрабатывать, и мы сделали все возможное для оптимизации наших запросов. Итак, вот (псевдо) структура таблицы:
[user] (approx. 40,000 rows, 37 cols):
id INT (pk)
content_group_id INT (fk)
[username] VARCHAR(20)
...
[content_group] (approx. 200,000 rows, 5 cols):
id INT (pk)
title VARCHAR(20)
...
[content] (approx. 1,000,000 rows, 12 cols):
id INT (pk)
content_group_id INT (fk)
content_type_id INT (fk)
content_sub_type_id INT (fk)
...
[content_type] (2 rows, 3 cols)
id INT (pk)
...
[content_sub_type] (8 rows, 3 cols)
id INT (pk)
content_type_id INT (fk)
...
Мы ожидаем, что количество этих строк значительно возрастет (в частности, таблицы user, content_group и content). Да, в пользовательской таблице довольно много столбцов, и мы определили некоторые из них, которые можно переместить в другие таблицы. Есть также куча индексов, которые мы применили к затронутым таблицам, которые помогли.
Большие проблемы с производительностью связаны с хранимыми процедурами, которые мы используем для поиска пользователей (включая присоединения к таблице содержимого в поле content_group_id). Мы пытались изменить предложения WHERE
и AND
, используя различные подходы, и мы думаем, что получили их настолько хорошо, насколько могли, но все же это слишком медленно.
Еще одна вещь, которую мы пробовали, но которая не помогла, заключалась в том, чтобы поместить индексированное представление для таблиц пользователей и содержимого. При этом не было заметного прироста производительности, поэтому мы отказались от этой идеи из-за дополнительного уровня сложности, связанного с наличием уровня представления.
Итак, какие у нас есть варианты? Мы можем придумать несколько, но все они имеют свои плюсы и минусы:
Денормализация структуры таблицы
Добавьте несколько ограничений прямого внешнего ключа между таблицей пользователя и контентом, чтобы для каждого подтипа контента был другой внешний ключ в таблице контента.
Плюсы:
- Присоединение к таблице содержимого будет более оптимальным с использованием ее первичного ключа.
Минусы:
- В наши существующие хранимые процедуры и код веб-сайта будет внесено много изменений.
- Поддерживать до 8 дополнительных внешних ключей (более реалистично, мы будем использовать только 2 из них) будет далеко не так просто, как текущий единственный ключ.
Больше денормализации структуры таблицы
Просто продублируйте нужные нам поля из таблицы контента в пользовательскую таблицу напрямую.
Плюсы:
- Больше никаких соединений с таблицей содержимого, что значительно сокращает работу, которую должен выполнять SQL.
Минусы
- То же, что и выше: дополнительные поля для поддержки в пользовательской таблице, изменения в SQL и коде веб-сайта.
Создайте слой индексации среднего уровня
Используя что-то вроде Lucene.NET, мы поместили слой индексации над базой данных. Теоретически это улучшит производительность всего поиска и в то же время снизит нагрузку на сервер.
Плюсы:
- Это хорошее долгосрочное решение. Lucene существует для повышения производительности поисковых систем.
Минусы:
- В краткосрочной перспективе стоимость разработки будет намного выше, и нам нужно решить эту проблему как можно скорее.
Итак, это то, что мы придумали, и на данном этапе мы думаем, что второй вариант является лучшим - я знаю, что у денормализации есть свои проблемы, однако иногда лучше пожертвовать архитектурной чистотой, чтобы получить прирост производительности, поэтому мы готовы оплатить эту стоимость.
Есть ли какие-то другие подходы, которые могли бы работать для нас? Есть ли какие-либо дополнительные плюсы и/или минусы в подходах, которые я изложил выше, которые могут повлиять на наши решения?