我一直在研究Coldfusion/MS SQL多年,這是我見過的最奇怪的問題之一。問題本身已經得到解決,但我並不真正瞭解發生了什麼;這個問題試圖弄清楚可能的原因。慢速查詢,CF 9&MSSQL 2008;腐敗的執行計劃?
的問題
在穩定的生產環境中,沒有明顯的原因,一個查詢開始返回圍繞1,000-1,500 MS(比平時慢約10倍)。我可以把它隔離到這一點:
<cfquery datasource="#ds#" name="query">
select 1
from eLearning.v_courseCompletion cc
where
cc.memberIncId = <cfqueryparam value="3" cfsqltype="cf_sql_integer"> and
cc.courseId = <cfqueryparam value="25" cfsqltype="cf_sql_integer"> and
cc.currentCourseCompleted = 1
</cfquery>
有什麼奇怪的是,這種行爲是在一個循環中時加重,即使有一個迭代,就像這個例子:
<cfloop from="1" to="1" index="i">
<cfquery datasource="#ds#" name="query">
select 1
from eLearning.v_courseCompletion cc
where
cc.memberIncId = <cfqueryparam value="3" cfsqltype="cf_sql_integer"> and
cc.courseId = <cfqueryparam value="25" cfsqltype="cf_sql_integer"> and
cc.currentCourseCompleted = 1
</cfquery>
</cfloop>
這應該和上面完全一樣吧?該循環應該沒有效果,但相反,該測試運行速度慢大約10倍,在7,000-16,000毫秒之間返回。這是如何檢測到問題的;查詢(埋在一個對象方法中)正在從循環體中調用,如果循環迭代超過5或6次請求超時。
對我來說,這表明了Coldfusion方面的一個問題,但重新啓動服務,或者實際上機器什麼都沒做。
同時,一旦被隔離,我發現對查詢本身進行任何更改都會導致性能恢復到預期水平,大約在150-190毫秒之間。例如:
- 改變所選擇的字段(即
select *
) - 卸下表別名(
cc
) - 具有內嵌值
- 卸下任何條件更換或者
<cfqueryparam>
這些更改中的任何一個都「固定」了這個問題,但是在運行原始查詢時,性能問題會返回。
解決方案
在這一點上我猜查詢的執行計劃已經損壞或什麼的,做some Googling,跑DBCC FREEPROCCACHE
對DB服務器。這立即修復了問題。太好了,問題就解決了....
問題
從那以後,雖然,我已經做了一點研究和共識似乎是,執行計劃「沒有遭到損壞」。有some talksimilar problems與存儲過程和parameter sniffing發生,但我沒有在這裏使用任何sp。我們選擇一個相當複雜的視圖,但是(eLearning.v_courseCompletion
)嵌套連接。這是問題嗎?
基本上,這裏究竟發生了什麼?如何阻止它再次發生?
..和地獄是連接循環在CF?!?
版本
- ColdFusion的9.0.2.282541(64位)
- 的SQL Server Express 10.50.4297(64位)
- 兩臺服務器都贏Server 2008 R2的數據中心(64位)
啊太棒了,這很有道理。瞭解爲什麼從一個循環內運行它(甚至一次迭代)會如何影響性能?謝謝 – Molomby 2014-10-10 05:27:31
不,循環聽起來不像罪魁禍首。我會責怪循環提供的其他一些情況,例如索引變量或使循環看起來像是責怪的東西。另外,你幾乎總是可以避免在循環中運行cfquery。實際上這很有意義。 – 2014-10-10 12:23:38
謝謝你的跟進,但我向你保證,在循環中沒有其他東西可以(應該)造成這種情況;上面提到的代碼塊是直接從我的測試用例中提取出來的(前後加上'getTickCount()')。循環的索引(或項目)變量根本不被查詢引用,循環體中沒有其他東西。據推測,在循環編譯到Java期間,某些事情會發生故障?如果我能重現這個問題,我會深入一點。 – Molomby 2014-10-13 00:23:17