У меня есть 2 таблицы (не может изменить их)SQL Server родитель-ребенок присоединиться и низкая производительность запроса
Parent (id, date, amount)
Child (parent_id, key, value)
индексы
Parent.pk (id)
Parent.idx1 (id, date) include (amount)
Child.pk (parent_id, key)
Child.idx1 (parent_id, key, value)
и запрос
select sum(amount)
from Parent as p
left outer join Child as c1 on c1.parent_id = p.id and c1.key = 'X'
left outer join Child as c2 on c2.parent_id = p.id and c2.key = 'Y'
where p.date between '20120101' and '20120131'
and c1.value = 'x1'
and c2.value = 'y1'
Проблема производительности.
Родитель имеет ~ 1 500 000 записей и ребенка ~ 6 000 000 записей
Берут 1
Этот запрос занимает ~ 3сек, который слишком много для моего сценария - он должен быть менее нескольких миллисекунд.
План выполнения показывает мне, что SQL Server выполняет индексное сканирование на Parent.idx1
, а затем объединяет объединение с Child.idx1
кластеризованным индексом поиска - что не является оптимальным, потому что он сканирует все 1500000 записей, даже если я их фильтрую по дате.
Take 2
Когда я изменяю Parent.idx1
в
Parent.idx1 (date, id) include (amount)
Sql сервер выбирает кластерный индекс сканирования на Parent.pk
и чем снова слиянием с Child.idx1
. Время выполнения ~ 6 с.
Возьмите 3
Когда я заставить его использовать Parent.idx1 (date, id) include (amount)
затем сортирует результат до слияния и время выполнения еще хуже ~ 11s.
Возьмите 4
Пытался создать индексированного представления, но не может использовать его из-LEFT OUTER JOIN.
Есть ли способ сделать такой запрос - родитель-ребенок объединяется с фильтрами на обоих из них - быстрее?
Без дезадаптации.
Update 2013-07-04:
Для тех, ответив использовать INNER JOIN - Да, это намного быстрее, но я не могу его использовать.
Я показал здесь упрощенную версию того, что мне действительно нужно.
Мне нужно создать SQL-представление для таблиц MS Dynamics NAV «G/L Entry» (родительский) и «Ledger Entry Dimension» (Child), чтобы я мог прочитать его из этого приложения. Полный вид выглядит это прямо сейчас:
create view analysis
as
select
v.id as view_id
, p.date
, p.Amount
, c1.value as value1
, c2.value as value2
, c3.value as value3
, c4.value as value4
from Parent as p
cross join analysis_view as v
left outer join Child as c1 on c1.parent_id = p.id and c1.key = v.key1
left outer join Child as c2 on c2.parent_id = p.id and c2.key = v.key2
left outer join Child as c3 on c3.parent_id = p.id and c3.key = v.key3
left outer join Child as c4 on c4.parent_id = p.id and c4.key = v.key4
где analysis_view содержит 8 записей в данный момент и выглядит следующим образом: analysis_view (id, key1, key2, key3, key4)
и затем ПРИМЕНЕНИЕ может запросить его, как это
select sum(amount)
from analysis
where view_id = 1 and date between '20120101' and '20120131'
and value1 = 'x1'
and value2 = 'x2'
или
select sum(amount)
from analysis
where view_id = 1 and date between '20120101' and '20120131'
and value1 = 'x1'
and value3 = 'z1'
MS Dynamics NAV уже имеет нормализованную таблицу для нее и запросы от нее быстрые, но в нашем случае они огромны (~ 10 ГБ) и блокируют всю систему примерно на один час, когда кто-то создает новый анализ. Также NAV не знает, как создавать соединения, поэтому я должен определить его на стороне SQL Server.
Являются ли «X» и «Y» единственными значениями 'key'? –
Предполагаете ли вы рассчитывать сумму для записи дважды, если у нее есть как ребенок с ключом X, так и ключ Y? Или вы должны использовать сумму для суммирования, если у нее есть ребенок X или Y? Потому что вы делаете первое, но второе гораздо чаще. –
«Менее нескольких миллисекунд» подразумевает, что все необходимые данные будут в кеше или любые операции ввода-вывода будут выполняться на SSD, возможно, в RAID-массиве, чтобы улучшить пропускную способность чтения. – HABO