2011-10-20 61 views
1

我正在運行帶有多個連接的存儲過程,其中一個包含超過600,000條記錄的表。問題是這個過程非常緩慢,需要幾分鐘才能執行。我們編制了相關表格列,但仍然沒有運氣。SQL Server加速查詢

我們可以做些什麼來幫助提高性能?該查詢發佈在下面。

感謝

with CTE 
as 
(
select * from 
(
    select distinct c.ContactId, c.FirstName, c.LastName, 
    (select top 1 ce.Email from dbo.ContactEmails as ce where ce.ContactId = c.ContactId and ce.IsPrimary = 1) as Email, 
    comp.CompanyName, j.JobName, c.MobileNumber, c.OfficeNumber, cse.DateSent, MAX(cse.DateSent) over(partition by ce.email) as maxdate 

    from dbo.ContactSentEmails as cse 

    join dbo.ContactEmails as ce on cse.ContactId = ce.ContactId 
    join dbo.Contacts as c on ce.ContactId = c.ContactId 
    left join dbo.Jobs as j on c.JobId = j.JobId 
    left join dbo.Companies as comp on c.CompanyId = comp.CompanyId 

    join dbo.StaffProjects as sp on cse.StaffProjectId = sp.StaffProjectId 
    join dbo.Staff as s on sp.StaffId = s.StaffId 
    join dbo.Projects as p on sp.ProjectId = p.ProjectId 

    where (@ContactSourceId = -1 or c.ContactSourceId = @ContactSourceId) 
    and (@FirstName = '' OR c.FirstName LIKE '%' + @FirstName + '%') 
    and (@LastName = '' OR c.LastName LIKE '%' + @LastName + '%') 
    and (@EmailAddress = '' OR ce.Email LIKE '%' + @EmailAddress + '%') 
    and (@StaffId = -1 or sp.StaffId = @StaffId) 
    and (@ProjectId = -1 or sp.ProjectId = @ProjectId) 
    and (@OfficeId = -1 or p.OfficeId = @OfficeId) 
    and cse.DateSent between CONVERT(datetime, @startDate) and CONVERT(datetime, @endDate) 

    group by c.ContactId, c.FirstName, c.LastName, Email,comp.CompanyName, j.JobName, c.MobileNumber, c.OfficeNumber, cse.DateSent 
) as tbContacts 
) 

select ContactId, FirstName, LastName, Email, CompanyName, JobName, MobileNumber, OfficeNumber from CTE where cte.DateSent = CTE.maxdate order by CTE.Email 
+4

與領先的通配符LIKEs可能是什麼傷害你在這裏。沒有多少索引會提高他們的表現。 –

+0

您還有(內部)加入下面的左(外部)連接。這些左連接將根據表格順序變成內連接。它看起來應該能夠在所有內部連接後移動而不會中斷查詢。 – billinkc

回答

2

很多缺陷!

缺陷1:如果不查看提供的值,就不能選擇計劃。

(@ContactSourceId = -1 or c.ContactSourceId = @ContactSourceId) 

如果@ContactSourceId是-1,那麼您有一個查詢執行計劃。如果ContactSourceId不是-1,則您有另一個查詢執行計劃。如果你想要選擇正確的執行計劃,你需要提供一個查詢,知道它應該被過濾掉,而不必查看變量的值。

既然你已經使用這個標準建造7次,有2^7周潛在的計劃和你得到正確的機率爲1/2^7 = 1/128 < 1%

您需要將這個查詢文本分解成128個不同的查詢 - 查詢優化器只會對你做不好的事情。


缺陷2:如果不使用優化搜索的搜索條件

其中一個128個的查詢是這樣的:假設@firstName供給和其他變量都沒有。在這種情況下,@FirstName是訪問聯繫人表的主要條件。

c.FirstName LIKE '%' + @FirstName + '%' 

如果你寫了關於剛剛Contacts表這個條件的查詢 - 就沒有索引,你可以添加到將要使用的聯繫人表。你註定要進行表掃描。瞭解有關SARGable搜索條件。


缺陷3:對每行的操作,每行都會得到相同的結果。

cse.DateSent between CONVERT(datetime, @startDate) and CONVERT(datetime, @endDate) 

爲什麼要在每一行上將變量轉換爲DateTime?在運行查詢之前進行轉換。


缺陷4:90%的時間鮮明的是一種精神寄託

distinct 
top 1 
group by 

這麼多的「給我一個」的查詢操作符是指查詢筆者只是想的東西,看到的堅持。簡化到實際意圖。我的猜測是獨特的是不需要的。如果您在不需要時添加獨特的功能 - 您仍然可以付錢!

+0

+1。通配符很慢,但DISTINCT像拇指一樣突出給我。一個相關的子查詢來獲得MAX(DateSent)'可能會更好,而不是DISTINCT。 –

+0

關於查詢計劃數量的好處,但我不會完全描述一個'缺陷'。但是,將關於分解爲單獨查詢的觀點可以作爲改善性能的良好模式(儘管這會使維護成本更高)。這是使用動態SQL或動態生成SQL的好處之一。 –

2

至於@Joe在你的問題中留言寫道,在LIKE運營商是昂貴的,特別是因爲你在前面加上通配符每個搜索字符串的開頭。衆多的OR運營商也是導致查詢性能不佳的一個原因。

請參閱Erland Sommarskog的經典文章Dynamic Search Conditions in T-SQL,瞭解編寫性能更好的「搜索」查詢的詳細介紹。

[此外,有什麼用SELECT TOP 1group by ...SELECT條款?幾乎在每列]

+1

我猜這個小組是因爲他錯誤地得到了一個組中沒有包含的列,所以只需將所有內容添加到小組中 – Purplegoldfish

+0

感謝您的回覆,我現在來看看那篇文章。選擇頂部是因爲可以有多個電子郵件地址設置爲主要電子郵件地址。我已經刪除了不需要的小組條款。謝謝 – user1005344

1

由於兩個@Joe和@Kenny說,該LIKE運營商很可能是你的問題的最大原因。解決這個問題可能會帶來最大的性能提升。調查full text search,看看它是否適合您的需求。

但是,我還會重新考慮您選擇電子郵件的方式,作爲select子句中的子選擇。這通常是在SQL Server中執行查詢的非常昂貴的方式。聯繫人是否可以有多個電子郵件地址IsPrimary = 1?如果不是,那麼只需加入主表FROM。如果他們可以有多個,請考慮編寫一個視圖(可能是索引視圖)以通過聯繫返回頂部電子郵件地址。然後你可以加入。

+0

是的,可以有多個電子郵件,其中主要= 1。我會看看你通過返回一個聯繫人並加入到你的建議。感謝郵件 – user1005344