2017-02-20 2 views
0

Ключевой частью этого вопроса является «Оптимально», что означает самое быстрое время возврата. У меня есть несколько таблиц, в которых есть информация, которую я хочу. У меня нет проблем с написанием самого запроса, просто пытаясь определить, каким будет самый быстрый способ получить информацию.Как оптимально получить записи из нескольких таблиц

  • аудита (Это основная таблица я хочу информации)
  • Order (Остальные таблицы я хочу ограниченные данные)
  • Работа
  • Кредиты

Дела они общий ресурс - это учетная запись и, следовательно, учетная запись. У меня есть учетная запись, которую я ищу раньше времени. К сожалению, таблица аудита не имеет прямого внешнего ключа в соответствующей таблице учетных записей и, таким образом, чтобы определить, принадлежит ли запись аудита к моему результирующему набору, мне пришлось бы присоединиться к таблице аудита и последующим 3 таблицам по одному проверьте, относится ли запись аудита к моему идентификатору учетной записи.

Например

Select a.* from [Audits] a JOIN [Orders] o ON a.RecordID = o.OrderID 
where a.RecordType = 'Order' and o.AccountID = @AccountID 
union 
select a.* from [Audits] a JOIN [Jobs] j on a.RecordID = j.JobID 
where a.RecordType = 'Job' and j.AccountID = @AccountID 
... 

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

EDIT 1

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

Create Table #AuditTemp (columns) 
Insert into #AuditTemp a.*, null as [Extra1], null as [Extra2] ... 
From [Audits] a 
Left Join [Orders] o ON a.RecordID = o.OrderID 
Left Join [Jobs] j ON a.RecordID = j.JobID 
Left Join [Credits] c ON a.RecordID = c.CreditID 
Where o.AccountID = @AccountID or j.AccountID = @AccountID ... 
Order By Time desc 
OFFSET @offset ROWS FETCH NEXT @PageSize ROWS ONLY 

Update #AuditTemp Set [Extra1] = o.[Column1] ... 
From [Orders] Where o.AccountID = @AccountID and #AuditTemp.RecordID = o.OrderID 
... 

Поэтому я получаю 20 записей, которые мне нужны, а затем заполняю их по одному, если они совпадают.

+0

Позвольте мне убедиться, что я правильно понял: поле «RecordID» из таблицы «Audit» может быть либо ордером, либо заданием, либо кредитом, и единственное, что они разделяют, это поле «AccountID»? –

+1

Это выглядит ... весело. Единственное, что приходит на ум, это использовать 'union all' вместо' union'. Это пропустит лишнюю сортировку и дедупликацию из 'union'. – SqlZim

+0

Какую версию и версию SQL Server вы используете? 'select @@ version' – SqlZim

ответ

1

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

CreateView [dbo].[SecondaryTables] 
AS 
SELECT OrderID AS RecordID, 'Order' AS RecordType, AccountID 
FROM [Orders] 
UNION 
SELECT JobID AS RecordID, 'Job' AS RecordType, AccountID 
FROM [Jobs] 
UNION 
SELECT CreditID AS RecordID, 'Credit' AS RecordType, AccountID 
FROM [Credits] 

Затем вы можете использовать этот вид присоединиться все данные, необходимые

SELECT [all your required fields] 
FROM [SecondaryTables] vw 
INNER JOIN [Audit] au 
ON vw.RecordID = au.RecordID AND vw.RecordType = au.RecordType 
LEFT OUTER JOIN [Orders] od 
ON vw.RecordID = od.OrderID AND vw.RecordType = 'Order' 
LEFT OUTER JOIN [Jobs] jo 
ON vw.RecordID = jo.JobID AND vw.RecordType = 'Job' 
LEFT OUTER JOIN [Credits] cr 
ON vw.RecordID = cr.CreditID AND vw.RecordType = 'Credit' 
WHERE vw.AccountID = @AccountID 

Если вы ожидаете результаты от всех таблиц (все ваши результаты всегда будут включать в себя данные из 3 таблицы), вам может изменить LEFT OUTER на INNER, чтобы улучшить производительность.

1

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

SELECT A.* 
FROM [Audits] A 

INNER JOIN (
    SELECT OrderID AS RecordID FROM [Orders] WHERE AccountID = @AccountID 
    UNION ALL 
    SELECT JobID AS RecordID FROM [Jobs] WHERE AccountID = @AccountID 
) AS DT 
ON A.RecordID = DT.RecordID 
WHERE A.RecordType IN ('Order','Job') 

Другой альтернативой является переход запроса UNION ALL в общее табличное выражение.

Оптимизатор SQL Server в наши дни очень хорош. Легко найти запрос, который стоит как минимум, но это не совсем то же самое, что и самый быстрый.

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

Учитывайте избирательность типа RecordType в таблице [аудитов]. Если Order and Job состоит из большинства ваших записей, то при добавлении индекса к RecordType мало пользы. Предположительно, у Order and Jobs есть индекс против AccountID?

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

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

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

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

Смежные вопросы