我正在构建一个执行具有多个连接的主查询的应用程序。然后,该查询数据可供整个应用程序在全局变量中使用。查询在每次刷新页面时刷新或获取最新结果集;所以它只是在请求的生命周期中处于相同的状态。
在本应用程序的其他部分,我有时会对此数据运行100个QoQ - 通常是递归函数调用的结果。然而,虽然QoQ是一个很棒的功能,但它并不是太快,有时在糟糕的一天,页面加载可能在3000 - 5000毫秒之间。它的速度还不够快。
我是否可以采用任何一种优化技术来使QoQ表现更快或者可能是另一种方法?我阅读了Ben Nadel关于Duplicate()函数的一篇有趣的文章 - 是否有使用它的范围,如果有,怎么做?
我很想听听你的想法。
不要担心疯狂的建议,这是个人项目所以我愿意承担风险。我正在使用与CF8兼容的Railo上运行它。
非常感谢, 迈克尔。
答案 0 :(得分:2)
在没有看到QoQ的代码和复杂性的情况下,很难确定最佳方法,但是您可以做的一件事是使用结构来索引QoQ之外的记录。使用QoQ的大部分开销是构建新的查询对象,并且使用struct write only方法比例如循环原始查询并进行比较更有效。
例如:
<!--- build up index --->
<cfset structindex = {} />
<cfset fields = "first,last,company" />
<cfloop list="#fields#" index="field">
<cfset key = "field:#field#,value:#q[field][currentrow]#" />
<!--- initialize each key (instead of using stuctkeyexists) --->
<cfloop query="q">
<cfset structindex[key] = "" />
</cfloop>
<cfloop query="q">
<!--- update each key with list of matching row indexes --->
<cfset structindex[key] = listappend(structindex[key], currentrow) />
</cfloop>
</cfloop>
<!--- save structindex to global variable --->
<!--- output rows matching index --->
<cfset key = "field:company,value:stackexchange" />
<cfoutput>
<cfloop list="#structindex[key]#" index="row">
#q.last[row]#, #q.first[row]# (#q.company[row]#)<br />
</cfloop>
</cfoutput>
如果这与您的需求不匹配,请提供QoQ语句的一些示例以及主查询中有多少条记录。
答案 1 :(得分:1)
首先,我会查看主查询所花费的时间。如果它可以缓存一段时间并占用了大量的页面加载时间,我会缓存它。
接下来,我会看一下递归调用。如果它们可以迭代生成,那么可能会加快速度。我意识到这并不总是可行的。如果这不是你最大的时间下沉,我会感到惊讶。但是,如果不了解您正在做的事情,很难帮助您优化这一点。
我也可以考虑在DB服务器上编写一些递归QoQ的存储过程,这些存储过程旨在快速处理数据并有效地切片和切块。 CF不是 - QoQs非常有用,但不是速度恶魔(如你所知)。
最后,我会寻找直接过滤器,而不是使用QoQ。相反,我只是在标准cfoutput标记中对主查询运行循环,并在运行中进行过滤。这意味着您将循环遍历主查询一次,而不是主查询一次,结果查询一次。
答案 2 :(得分:1)
这里有两个主要的解决方案。首先,您可以使用QoQ之外的记录在CF中执行某些操作。我已经发布了我的建议。另一个是在db中做所有事情。我发现这样做的一种方法是使用子查询作为临时表。您甚至可以将sql语句保存在全局变量中,然后在与当前QoQ相同的位置引用它,但对数据库进行实际查询。它可能听起来比一次行程DB慢,然后很多QoQ,但实际上它可能不是有效索引。
select *
from (
#sqlstring#
) as tmp
where company = 'stackexchange'
我实际上已经为具有复杂标准的系统执行了此操作,该标准既包括用户应该访问的记录,也包括他们可以在这些记录中过滤的内容。采用这种方法意味着您始终知道内部记录的来源,而不是试图确保每个查询都正确地提取。
编辑: 实际上,在可能的情况下使用queryparams更安全(并且通常更有效)。我发现这可以通过包含sql语句的文件来完成......
select *
from (
<cfinclude template="master_subquery.cfm" />
) as tmp
where company = 'stackexchange'