Попробую словами, без кода, объяснить свою проблему.
Есть бизнес — объект, называемый Order. Каждый его экземпляр хранится в строке таблицы Orders.
В нем около 150 полей, значительная часть (около половины) из которых — это id элементов справочников (перечислений).
Чтобы сделать объект "доступным для отображения" есть View, которая называется OrdersView.
Исторически сложилось, что в самом начале в объекте было гораздо меньше полей,
потом новые поля добавлялись в объект, в таблицу(как NULLable поля) и во View (как LEFT OUTER JOIN).
И по всему этому хозяйству надо делать всякие сложные поиски, которые формулируются в терминах полей,
которые выдает View.
Со временем, по мере увеличения кол-ва полей, кол-ва справочников и кол-ва записей в таблицу Orders —
поиск работал все более медленно. В попытках ускорить его я попытался построить индексы по полям View.
И столкнулся с тем, что для View, использующего Left Outer Join — это невозможно
(получаю ошибку "Cannot create index on view "Test.dbo.OrdersView" because it uses a LEFT, RIGHT, or FULL OUTER
join, and no OUTER joins are allowed in indexed views. Consider using an INNER join instead.").
Теперь у меня есть несколько выходов, я вижу такие:
1) отказываеться от использования Left Outer Join (что фактичеси потребует, чтобы у меня в строках таблицы не было
NULL — значений, ну и вообще потребует некоторого изменения логики на уровне извлечения и записи данных).
2) перейти на SQL — базу данных, которая не обладает таким странным ограничением на одновременное использование LEFT OUTER
JOIN и индексирование полей View (например, на одну из версий Oracle)
3) Отказаться в этой задаче от реляционной базы вообще, и использовать какую нибудь нереляционную, например, MongoDB.
Фактически этот объект Order — это документ, у которого много полей. Похоже на то, что его удобно хранить в
документно — ориентированной базе.
Как Вы посоветуете мне решать эту проблему — хранения вообще и медленного поиска в частности?
Здравствуйте, SteeLHeaD, Вы писали:
SLH> Как Вы посоветуете мне решать эту проблему — хранения вообще и медленного поиска в частности?
В чем проблема хранения, я не понял. Проблему медленного поиска решать как обычно — анализировать планы и статистику выполнения конкретных запросов, искать узкие места и устранять их. Универсального решения нет.
И еще посоветую найти и прочитать, что же на самом деле означает "построить индексы по полям View" и откуда берутся ограничения.
Здравствуйте, SteeLHeaD, Вы писали:
SLH>Как Вы посоветуете мне решать эту проблему — хранения вообще и медленного поиска в частности?
Тебе нужны индексы на таблицу orders по полям с максимальной селективностью
Если у тебя сценарий вроде подбора товара и интернет-магазине, то лучше сделать на движке полнотекстового поиска, который поддерживает предикаты.
150 join-ов -- не криминал, если всё сделано правильно.
Индексируй таблицы, а не VIEW.
Если совсем невмоготу, выбрасывай VIEW, заменяй процедурой.
Вообще, там в использовании VIEW туча нюансов, но в принципе, view -- убийцы производительности,
и с ними достаточно трудно работать в смысле оптимизации. Но, подчёркиваю, в твоём конкретном случае
это может быть не так.
О конкретном случае: ты о нём говоришь ровно 0 слов, никакой информации.
А оптимизировать нужно и можно только конкретный случай, абстрактной оптимизации не
бывает. Это в твоём случае VIEW + ЗАПРОС, который его использует, да ещё и с
параметрами, которые есть в запросе и с данными в таблицах.
И по всему этому хозяйству надо делать всякие сложные поиски, которые формулируются в терминах полей,
которые выдает View.
Сложные поиски и без VIEW уже могут быть проблемой.
И столкнулся с тем, что для View, использующего Left Outer Join — это невозможно
(получаю ошибку "Cannot create index on view "Test.dbo.OrdersView" because it uses a LEFT, RIGHT, or FULL OUTER
join, and no OUTER joins are allowed in indexed views. Consider using an INNER join instead.").
Ну, логично. Кстати, ещё не может быть фильтров по полям таблицы, которая в LEFT JOIN.
Теперь у меня есть несколько выходов, я вижу такие:
1) отказываеться от использования Left Outer Join .
Нет.
2) перейти на SQL — базу данных, которая не обладает таким странным ограничением на одновременное использование LEFT OUTER
JOIN и индексирование полей View
Нет такой базы, я подозреваю. К тому же тебе не нужно индексировать VIEW, это почти бесполезно.
3) Отказаться в этой задаче от реляционной базы вообще, и использовать какую нибудь нереляционную, например, MongoDB.
Это вообще бред. Кстати, типичный для "неосиляторов РСУБД". В NOSQL такие же данные, и такие же по ним индексы.
Ровно такие же.
Как Вы посоветуете мне решать эту проблему — хранения вообще и медленного поиска в частности?
Ну тут ничего конкретного нет в виде вопросов, поэтому ничего конкретного посоветовать нельзя.
Даже задача по сути неясна, только вопли ужоса... Так что только всё то, что было уже написано.
Здравствуйте, SteeLHeaD, Вы писали:
SLH>Есть бизнес — объект, называемый Order. Каждый его экземпляр хранится в строке таблицы Orders. SLH>В нем около 150 полей, значительная часть (около половины) из которых — это id элементов справочников (перечислений).
Что-то слабо вериться, что Ордер может иметь 150 атрибутов. Походу, вы изначально запихали в Ордер то, что ему не принадлежит, отсюда последующие головняки.
Здравствуйте, SteeLHeaD, Вы писали:
SLH>Как Вы посоветуете мне решать эту проблему — хранения вообще и медленного поиска в частности?
Проблема хранения у вас решена корректно. Необязательные поля объявлены Null, повторяющиеся значения вынесены в справочники.
Проблему медленного поиска нужно решать путём профилирования и выпиливания узких мест.
Выпиливание узких мест = построение индексов. Для таблиц. Индексы для view (или материализованные view) — это очень специфическое средство, которое применимо не всегда.
Профилирование = просмотр планов запросов, которые вас не устраивают.
Ваше описание подходит под одну или несколько проблем:
1. В таблицах-справочниках нет индексов, которые позволяют быстро найти то, что нужно. Пример: во View есть ссылка из Order.CityID в таблицу City(ID, Name). Поиск делаем Where OrderView.CityName like 'Ново%' — получаем full scan таблицы городов. Решение: делаем индекс на city по (Name, Id), получаем index seek вместо full scan.
2. В основной таблице нет индексов, которые позволяют быстро найти то, что нужно. Пример: нет индекса, начинающегося с Order.СityID. Результат: Join у нас проходит в стиле inner loop. Решение: добавляем индекс пo (СityID, OrderID), запрос Where OrderView.CityName like 'Ново%' начинает летать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.