我继承了一个应用程序,可以在很多地方执行以下类型的查询:
select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = getFooF4()
getFooF4看起来像这样
Public Function getFooF4()
Dim dbCurrent As Database
Dim rstBar As Recordset
Set dbCurrent = CurrentDb
Set rstBar = dbCurrent.OpenRecordset("Bar", _
dbOpenDynaset, _
dbSeeChanges)
getFooF4 = rstBar![myF4]
''yes this appears broken... Bar only contains one row :-/
rstBar.close
Set rstBar = Nothing
dbCurrent.close
Set dbCurrent = Nothing
End Function
'' Note: in my experimentation getFooF4 only runs once during the
'' execution of the query.
这最终运行得相当慢。如果我使用常量从查询中删除getFooF4():
select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = 123456
或参数:
select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = [myFooF4]
或加入:
select foo.f1, foo.f2, foo.f3
from foo
INNER JOIN bar ON bar.myF4 = foo.f4
它运行得更快。
为什么?
规范:在MS Access 2003中编写并运行的应用程序,后端数据库是SQL Server 2008。
答案 0 :(得分:4)
使用GetFooF4的示例既不能由Sql Server优化,也不能由Access优化。并且一直重新打开这个rs是非常低效的。作为一般规则,请避免在查询中使用Access特定功能或代码。这可以防止Acces“按原样”向Sql server发送查询。它必须下载全部数据并在本地处理,这意味着更多的流量和更低的速度 见http://msdn.microsoft.com/en-us/library/bb188204(v=sql.90).aspx#optaccsql_topic2
答案 1 :(得分:2)
提高效率的两件事(尽管只有一个或另一个适用于这样的特定情况):
为您的函数定义一个返回类型,即Public Function getFooF4()
应该是Public Function getFooF4() As Long
(或者任何适当的数据类型。如果没有明确的数据类型,它将返回一个变体。实际上,永远不会有一个VBA函数应该缺少一个返回类型声明 - 如果它返回一个变量(这是非常合理的,特别是当你需要在某些情况下返回Null时),用As Variant
定义它。它是一些其他数据类型,明确定义它。
在SQL中声明一个参数,以便查询优化器可以在计算查询计划时使用该信息。当您的WHERE子句使用函数提供标准时,这不适用,但如果您使用对控件上的字段的引用,则替换为:
select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = Forms!MyForm!MyControl
......用这个:
PARAMETERS [Forms]![MyForm]![MyControl] Long;
select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = Forms!MyForm!MyControl
现在,在任何一种情况下,由于函数/参数在WHERE子句中,它只需要解析一次,所以即使函数效率低下(如此情况,初始化数据库变量)并打开一个记录集),它实际上并没有太大的区别。
要考虑的另一件事是用一个简单的DLookup()替换该函数,该设计就是为了这个目的而设计的。或者,由于值来自表,您应该能够将其加入到单行表中:
select foo.f1, foo.f2, foo.f3
from foo INNER JOIN Bar ON foo.f4 = Bar.MyF4
这可以通过查询优化器进行最大程度的优化,因为它根本没有任何未知数 - 查询优化器将知道它需要了解的有关数据类型和表统计信息的所有内容,并且可以选择最有效的检索方法。 / p>
答案 2 :(得分:1)
它与以下相比如何:
r = getFooF4()
select foo.f1, foo.f2, foo.f3
from foo
where foo.f4 = r
如果这和原作一样慢,那么答案很简单:getFooF4()函数是缓慢的部分。