[英]CFML & SQL - Performance Increase?
好的,所以我写了一个会过滤一些产品的查询,但是,我需要尝试进一步调整这个查询以允许更多的过滤器。 我有点做了,但是,它需要两倍的时间,我的意思是页面加载和完全渲染大约需要5秒以上,这在我看来还不够好。 我的意思是它有效,但它对于商业发布来说太慢了。
我假设它在下面复制的功能要慢得多, 但遗憾的是我不确定我怎么能做到这一点? - 我想不出一种方法可以编写一个基本上不需要使用我编写的函数的查询。
我猜 ,最好的方法是以某种方式将两个查询合并在一起,另外一个用于其他过滤器,这些过滤器不适用于我现有的那个? - 我不完全确定。
所以无论如何,这里有一些代码 : -
<cfset row = 0>
...
<cfquery name="query" datasource="ds">
DECLARE @st TABLE (ID int, z varchar(50))
DECLARE @tc int
<cfloop array="#refineArr#" index="x">
<cfset row ++>
<cfoutput>
INSERT INTO @st VALUES ('#IDArr[row]#', '#x#')
</cfoutput>
</cfloop>
SELECT @tc = COUNT(DISTINCT ID)
FROM @st
SELECT tbl.code
FROM Table1 tbl
INNER JOIN @st T
ON T.ID = tbl.ID
AND tbl.V = T.z
INNER JOIN Table2 tbl2
ON tbl.ID = tbl2.ID
WHERE tbl.code IN (<cfqueryparam list="yes" value="#valuelist(getallcodes.code)#">)
GROUP BY tbl.code
HAVING COUNT(tbl.ID) = @tc
</cfquery>
只是为了澄清,这个查询工作正常,没有任何问题。 这两个数组只是在此查询之前生成,IDarr数组只是某个类别中所有 ID的数组,然后根据用户输入的优化生成refineArr数组。 - 它们都被强制为相同的长度,因此当该索引不存在时,它永远不会尝试为一个数组获取索引'x'。
正如你可能已经猜到了,行了“getallcodes.code”,只是得到所有代码应该有一定的猫/子猫下显示所有产品,等等。
好的,对于下一部分,由于滤波器种类不同,我需要允许范围发生,日期和测量。 但是,暂时忽略测量部分,结果是存储在数据库中的数据全部搞砸了,无法进行测量。
我最初尝试创建一个函数,它工作,但它不是那么快,并且运行调用函数,我最初写这个:
<cfset ranges = ['Months','Period','SMonths']>
<cfset tc = 0>
<cfset tempQ = query>
...
<cfloop array="#ranges#" index="i">
<cfset tc ++>
<cfif i contains 'month' or i contains 'period'>
<cfset tempQ = rangesFnc(tempQ, Int(tc), ToString(i))>
</cfif>
</cfloop>
请记住,我还没有写完这个函数,我知道它仍然有点凌乱,至于数组,它们实际上只是一些变量的集合,这些变量对于进行其他改进至关重要。
<cffunction name="rangesFnc">
<cfargument name="q" type="query" required="true">
<cfargument name="i" type="numeric" required="true">
<cfargument name="s" type="string" required="true">
<cfset minArr = '#minf#,
#minh#,
#minh2#,
#minm#,
#mins#'>
<cfset maxArr = '#maxf#,
#maxh#,
#maxh2#,
#maxm#,
#maxs#'>
<cfset min = listGetAt(minArr, i)>
<cfset max = listGetAt(maxArr, i)>
<cfquery name="tempq" datasource="ds">
WITH q AS (
SELECT DISTINCT tbl.code,
CASE
WHEN tbl.V = 'January' THEN 1
WHEN tbl.V = 'February' THEN 2
WHEN tbl.V = 'March' THEN 3
WHEN tbl.V = 'April' THEN 4
WHEN tbl.V = 'May' THEN 5
WHEN tbl.V = 'June' THEN 6
WHEN tbl.V = 'July' THEN 7
WHEN tbl.V = 'August' THEN 8
WHEN tbl.V = 'September' THEN 9
WHEN tbl.V = 'October' THEN 10
WHEN tbl.V = 'November' THEN 11
WHEN tbl.V = 'December' THEN 12
ELSE 0
END AS xdate
FROM Table1 tbl
INNER JOIN Table2 tbl2
ON tbl.ID = tbl2.ID
WHERE tbl2.name LIKE <cfqueryparam value="%#s#%">
AND tbl.code IN (<cfqueryparam value="#valueList(q.code)#" list="yes">)
)
SELECT code
FROM q
WHERE xdate <= <cfqueryparam value="#Int(max)#">
AND xdate >= <cfqueryparam value="#Int(min)#">
</cfquery>
<cfreturn tempq>
</cffunction>
我想为任何语法突出问题道歉,以及它有点混乱的事实。 除了我必须留下很多信息的事实。 源代码本身看起来非常不同,但这是故意的,我只是在这里复制一个虚拟示例,因为我的责任是确保我不会暴露太多关于网页结构的信息我是我知道,工作,傻,但规则是规则。
我也只添加了'Int()'或'ToString()'之类的函数来确保它按预期工作,就是这样,仅此而已,它可能甚至不需要现实地说。
这更像是一个评论,但它太长了。
我真的不喜欢<cfloop>
来加载临时表。 您的SQL Server将无法缓存查询,并且每次都必须重新解析它。 我和#valuelist(getallcodes.code)#
有类似的问题#valuelist(getallcodes.code)#
我宁愿多值参数通过永不改变的东西拉出数据。
<!--- Generate XML of data --->
<cfquery>
DECLARE @st TABLE (ID int, z varchar(50))
DECLARE @tc int
DECLARE @xmlIDArr xml = <cfqueryparam value="#xmlIDarr#">
INSERT INTO @st
SELECT tbl.Col.value('id', 'int'), tbl.Col.value('z', 'varchar(50)')
FROM @xmlIDArr.nodes('/data') tbl(Col)S
SELECT @tc = COUNT(DISTINCT ID)
FROM @st
SELECT tbl.code
FROM Table1 tbl
INNER JOIN @st T
ON T.ID = tbl.ID
AND tbl.V = T.z
</cfquery>
有关其他示例: 在超过2100个值上选择IN
这里有一些代码评论点(这是一个答案,因为格式比注释更漂亮):
初始查询
1)在查询中移动行变量并对其进行范围化。 <cfset row = 0>
在查询之前只是在寻找麻烦。
2)将INSERT
循环。 SQL 2008可以插入多个值。 无需多次访问数据库。
INSERT INTO @st
VALUES
<cfloop array="#refineArr#" index="x">
<cfset row++>
<cfoutput>('#IDArr[row]#','#x#')</cfoutput>
<cfif row LT ArrayLen(refineArr)>,</cfif>
</cfloop>
3)我不知道cf页面的其余部分是什么样的,但我的直觉是cfquery可以重构为单个SELECT而不需要temp @st表变量。
下一部分
没有看到更多的代码,我不确定如何最好地优化它。 可以同时有多个过滤器(即Months and Periods
过滤?
1)再次确定范围。 这里有很多松散的变量。 有些可能没有必要。
2)这里需要循环吗? 再没有更多的代码,我不知道它的目的是什么。
3)在你的循环中, i contains month or i contains period
是对i
中的值进行大量额外解析,并且它可能并不总是返回预期的值。 如上所述,它也将返回SMonths
。
4)我假设tempQ=query
只是第一部分查询的副本,对吗? 这需要吗?
功能本身
1) minArr
和maxArr
>>数组是否会传递给函数? 或者minf, minh....
变量会被传入吗? 不应从函数外部访问它们。 您应该能够完全自己运行该功能(它应该是它自己的CFC)。
2)它们被命名为数组,但它们包含列表。 名称应与其意图一致。
3)您将变量重命名为tempq
并将其设置为之前的查询,然后在函数内部创建另一个名为tempq
查询。 这可能会造成混淆哪个tempq
如果再沿用下来的页面,您试图访问。
4) Table1.V
的数据类型是Table1.V
? 你能用一个SQL函数来返回日期名称的数字吗?
5)在WHERE
子句中,使用tbl2.name LIKE....
这应该移到Table2
的INNER JOIN
中。 `INNER JOIN Table2 tbl2 ON tbl.ID = tbl2.ID AND tbl2.name LIKE()
6)我不认为你在这个查询中需要CTE。 你只需构建xdate
来过滤CTE。 将整个块添加到WHERE
子句中。
最后
我花了将近20年的时间在专有或更严格的环境中工作,所以我完全理解保护应用程序源的必要性。 它可能令人沮丧,但它有时是一种必要的邪恶。 我在这里比我想要的更加罗嗦,但我希望它确实有帮助。 正如我之前所说,在不了解应用程序的意图的情况下,我只能希望我已经引导您走上正确的道路,我希望我的建议至少在性能上有所改善。
祝好运。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.