我们正在从ColdFusion 9升级到ColdFusion 2016,我们注意到整体性能下降。我们进行了几次模拟以提供更多洞察力。下面是一个脚本,它提供了性能下降的一个很好的示例。该脚本构建一个查询,然后从查询中创建一个结构。
\n
我们有两台服务器具有完全相同的硬件配置。一台服务器在Windows 2008 / ColdFusion Server 9 Enterprise(Java版本1.6.0_14)上运行,另一台服务器在Windows 2016 / ColdFusion 2016 Standard(Java版本1.8.0_112)上运行。两个ColdFusion服务器都具有相同的最小JVM堆大小(5024 MB)和最大JVM堆大小(5048 MB)。
ColdFusion 9服务器上的性能提高了4倍。有人可以解释为什么会发生这种情况以及如何解决这个问题吗?
更新
要排除任何其他会降低ColdFusion的进程,我在同一个虚拟机上安装了ColdFusion 9,ColdFusion 11和ColdFusion 2016,所有这些都使用了内置的Web服务器。默认安装设置。结果:ColdFusion 9最快,紧随ColdFusion 11. ColdFusion 2016慢得多。
更新2 对脚本进行了一些更改,因此更清楚这个脚本在做什么。
更新3 结果可以在这里查看: http://136.144.177.152/test2.asp或 http://136.144.177.152/test-toma.asp或 http://136.144.177.152/test-ag.asp 请注意,代码实际上已处理,因此每次加载页面时,结果都会略有不同。
此外,我想指出我不是在尝试优化此代码。我试图制作一个非常简单的可重复的例子。唯一的目的是指出性能上的差异并找到原因和解决方案。
更新4 做了一些额外的测试,发现了潜在的问题。出于某种原因,以下代码在coldfusion 2016 / Windows 2016上非常慢:
<!--- Machine info --->
<cfset runtime = createObject("java", "java.lang.System")>
<cfset props = runtime.getProperties()>
<cfset env = runtime.getenv()>
<Cfoutput>
coldfusion: #SERVER.ColdFusion.ProductVersion# #SERVER.ColdFusion.ProductLevel#<br>
java.version: #props["java.version"]#<br>
java.vm.name: #props["java.vm.name"]#<br>
os.name: #props["os.name"]#<br>
PROCESSOR_IDENTIFIER: #env["PROCESSOR_IDENTIFIER"]#<br>
PROCESSOR_ARCHITECTURE: #env["PROCESSOR_ARCHITECTURE"]#<br>
NUMBER_OF_PROCESSORS: #env["NUMBER_OF_PROCESSORS"]#<br><Br>
</Cfoutput>
<!--- Create a query --->
<cfset myQuery = QueryNew("Name, Time, Advanced", "VarChar, Time, Bit")>
<cfset testQuery = QueryNew("ColumnA,ColumnB,ColumnC,ColumnD,ColumnE,ColumnF,ColumnG,ColumnH,ColumnI,ColumnJ,ColumnK,ColumnL,ColumnM,ColumnN","VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar")>
<!--- Populate the query --->
<Cfloop from=1 to=300 index="x">
<cfset QueryAddRow(testQuery, 1)>
<cfloop index="intLetter" from="#Asc('A')#" to="#Asc('N')#" step="1">
<cfset temp = QuerySetCell(testQuery, "Column#chr(intLetter)#", "Row #x# column #intLetter#", x)>
</cfloop>
</cfloop>
<Cfset init = GetTickCount()>
<!--- Query to structure --->
<Cfset queryToStruct = structNEw()>
<cfloop query="testQuery">
<Cfset init2 = GetTickCount()>
<cfset queryToStruct[testQuery.currentrow] = structNew()>
<cfset queryToStruct[testQuery.currentrow]['ColumnA'] = structNew()>
<cfloop list="#testQuery.columnList#" index="key">
<cfset queryToStruct[testQuery.currentrow]['ColumnA'][testQuery[key][testQuery.currentrow]] = testQuery[key][testQuery.currentrow]>
</cfloop>
<cfoutput>#x#:#GetTickCount()-init2#<br></cfoutput>
</cfloop>
<cfoutput>-----------<br><b>#GetTickCount()-init#</b><br><br><Br></cfoutput>
<!---Cfdump var=#queryToStruct# --->
我发现非常奇怪的是更新查询值并不慢。 E.g。
<cfset tmp = testQuery['ColumnA'][testQuery.currentrow]>
所有结果均可在此处找到:http://136.144.177.152/test5.asp或http://136.144.177.152/test6.asp。我还在笔记本电脑上安装了coldfusion 2016,发现没有性能问题。我也尝试在Windows 2012机器上安装coldfusion 2016。在这里,我发现了相同的性能问题。
更新5 根据Tomalak的建议,我删除了索引访问符号。这显然是coldfusion 2016上的性能问题。实际结果可以在http://136.144.177.152/bug-adobe.asp找到。我在adobe为此问题打开了一个错误https://tracker.adobe.com/#/view/CF-4201966。
答案 0 :(得分:2)
我真的无法重现这个问题。这在我的ColdFusion 2016上运行得非常快。我已经创建了QueryToStruct
代码的优化版本,但除此之外没有什么区别。
我没有可用的CF 9服务器,在测试时,这个代码在CF 9上的速度是4倍吗?
<!--- Machine info --->
<cfset runtime = createObject("java", "java.lang.System")>
<cfset props = runtime.getProperties()>
<cfset env = runtime.getenv()>
<cfoutput>
ColdFusion: #SERVER.ColdFusion.ProductVersion# #SERVER.ColdFusion.ProductLevel#<br>
java.version: #props["java.version"]#<br>
java.vm.name: #props["java.vm.name"]#<br>
os.name: #props["os.name"]#<br>
PROCESSOR_IDENTIFIER: #env["PROCESSOR_IDENTIFIER"]#<br>
PROCESSOR_ARCHITECTURE: #env["PROCESSOR_ARCHITECTURE"]#<br>
NUMBER_OF_PROCESSORS: #env["NUMBER_OF_PROCESSORS"]#<br>
<br>
</cfoutput>
<!--- Create a query --->
<cfset ROWNUM = 2000>
<cfset testColumns = "ColumnA,ColumnB,ColumnC,ColumnD,ColumnE,ColumnF,ColumnG,ColumnH,ColumnI,ColumnJ,ColumnK,ColumnL,ColumnM,ColumnN">
<cfset testTypes = "VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar ,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar,VarChar">
<cfset testQuery = QueryNew(testColumns, testTypes)>
<!--- Populate the query --->
<cfloop from="1" to="#ROWNUM#" index="x">
<cfset QueryAddRow(testQuery, 1)>
<cfloop from="#Asc('A')#" to="#Asc('N')#" index="intLetter">
<cfset QuerySetCell(testQuery, "Column#chr(intLetter)#", "#x#-#intLetter#", x)>
</cfloop>
</cfloop>
<!--- Convert the query to a struct --->
<cfset init = GetTickCount()>
<cfset converted = QueryToStruct(testQuery, "ColumnA")>
<cfoutput>
<b>My version:</b> #StructCount(converted)# rows, #GetTickCount()-init# ms<br>
</cfoutput>
<!--- Convert the query to a struct --->
<cfset init = GetTickCount()>
<cfset converted = QueryToStructOP(testQuery)>
<cfoutput>
<b>OP version:</b> #StructCount(converted)# rows, #GetTickCount()-init# ms<br>
</cfoutput>
<!--- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --->
<cffunction name="QueryToStruct">
<cfargument name="Query" type="query" required="yes">
<cfargument name="IndexColumn" type="string" required="yes">
<cfset var result = StructNew()>
<cfset var rowTemplate = StructNew()>
<cfset var key = "">
<cfset var thisRow = "">
<cfloop list="#Query.ColumnList#" index="key">
<cfset rowTemplate[key] = "">
</cfloop>
<cfloop query="Query">
<cfset thisRow = Duplicate(rowTemplate)>
<cfset result[Query[IndexColumn][Query.CurrentRow]] = thisRow>
<cfloop collection="#thisRow#" item="key">
<cfset thisRow[key] = Query[key][Query.CurrentRow]>
</cfloop>
</cfloop>
<cfreturn result>
</cffunction>
<cffunction name="QueryToStructOP">
<cfargument name="Query" type="query" required="yes">
<cfset var queryToStruct = StructNew()>
<cfset var key = "">
<cfset var index = "">
<cfloop query="Query">
<cfset index = Query['ColumnA'][Query.CurrentRow]>
<cfset queryToStruct[index] = StructNew()>
<cfloop list="#Query.ColumnList#" index="key">
<cfset queryToStruct[index][Query[key][Query.CurrentRow]] = Query[key][Query.CurrentRow]>
</cfloop>
</cfloop>
<cfreturn queryToStruct>
</cffunction>
结果(这甚至不是服务器硬件,而且它是一个旧的CPU):
java.version: 1.8.0_162 java.vm.name: Java HotSpot(TM) 64-Bit Server VM os.name: Windows 7 ColdFusion: 2016,0,05,308055 Developer PROCESSOR_IDENTIFIER: Intel64 Family 6 Model 42 Stepping 7, GenuineIntel PROCESSOR_ARCHITECTURE: AMD64 NUMBER_OF_PROCESSORS: 4 My version: 2000 rows, 78 ms OP version: 2000 rows, 229 ms
答案 1 :(得分:2)
首先,您将CF 9 Enterprise与CF 2016 Standard进行比较。对于这个例子来说不应该是一个大问题,但是如果你在Standard上对整个应用程序进行回归测试,你就会看到问题。我以前的公司从9 Ent迁移到2016 Ent,我们看到的是全面的性能改进。当你看到瓶颈时,你应该总是考虑重构。这是升级的一个原因。
最大的问题是如何将query
转换为struct
。 CF 2016具有更多高级功能。将您的遗留流程与利用查询对象中的成员函数的遗留流程进行比较。
public array function arrayOfStructs(required query data) {
var results = [];
arguments.data.each(function(row) {
arrayAppend(results, arguments.row);
});
return results;
}
query
成员函数each()
将每个row
的内容引用为struct
。无需遍历每列,输入新密钥并分配值。繁荣!完成。快死了。
进行升级。 :)