访问2007年用户定义的函数加入缓慢

时间:2013-08-07 18:17:22

标签: performance join ms-access-2007 user-defined-functions

为什么在包含外连接的多个连接的查询中使用用户定义函数的查询会变慢?该函数的原因是修改字符串以便按数字排序。对字符串进行排序意味着100 < 99。该函数重新格式化99 as 099。所以,099 < 100。它允许其他非数字值保持不变。

问题查询使用带有连接的查询的函数。返回100行需要27秒。相同的查询,带有一个函数,但是在一个表上需要亚秒。使用连接查询查询的SQL替换是亚秒。没有带有连接的查询功能的查询是亚秒。主表是tblTests,有517行。函数操作的列是文本列fldPurity。

tblTests
fldTestsID    autonumber
fldPurity     Text.  field size 50. Indexed (Duplicates OK). Zero Length No. 

这是功能代码。注意不同的输入。

Public Function SortablePercent(ByVal pVar As Variant) As String
'------------------------------------------------------------------
' Purpose:   Formats a string that may contain numbers or text values.
'            The string percent may contain % or + characters. Ignore
'            those characters during comparison. A string may start with numeric
'            characters, but end with alpha characters. Compute the length of the resulting
'            numeric characters. Length 3 is 100, no change. Prepend leading zeros to length 2
'            or 1 numerics. Do not add prepend to values starting with text.

' Coded by:  2013-08-05 Henry Helgen
' Arguments: pVar: The string to be formatted.
' To Test:   From the debug (immediate) window:
'            X = "97+%"
'            ? SortablePercent(X)
'            097
'            X = "98"
'            ? SortablePercent(X)
'            098
'            X = "99.9"
'            ? SortablePercent(X)
'            099.9
'            X = "100"
'            Print SortablePercent(X)
'            100
'            X = "Reagent Grade"
'            ? SortablePercent(X)
'            Reagent Grade
'            X = "85% & 15% H2O"
'            ? SortablePercent(X)
'            085 & 15 H2O
'------------------------------------------------------------------
Dim strHold As String 'working string
Dim lenNum  As Integer 'length of leading integer portion of number

    ' remove whitespace, %, + characters
    strHold = Replace(Replace(Nz(Trim(pVar), ""), "%", ""), "+", "")

    If IsNumeric(strHold) Then 'the entire string is numeric
        lenNum = Len(CStr(Int(strHold)))
        'Fill with leading zeros
        strHold = Switch(lenNum = 3, strHold, lenNum = 2, "0" & strHold, lenNum = 1, "00" & strHold)
    ElseIf IsNumeric(Left(strHold, 2)) Then '
        strHold = "0" & strHold
    ElseIf IsNumeric(Left(strHold, 1)) Then
        strHold = "00" & strHold
    End If 'numeric

    SortablePercent = strHold

End Function

这是使用函数优先于连接查询的慢查询(27秒)

SELECT parm_TestConcatReferenceDatasetExposure.fldPurity, 
       SortablePercent([fldPurity]) AS temp2, Count(*) AS RcdCount
FROM parm_TestConcatReferenceDatasetExposure
GROUP BY parm_TestConcatReferenceDatasetExposure.fldPurity, 
         SortablePercent([fldPurity])
ORDER BY SortablePercent([fldPurity]);

这是使用一个表上的快速查询(<1秒)

SELECT tblTests.fldPurity, 
       SortablePercent([fldPurity]) AS temp2, 
       Count(*) AS RcdCount
FROM tblTests
GROUP BY tblTests.fldPurity, SortablePercent([fldPurity])
ORDER BY SortablePercent([fldPurity]);

这是快速查询没有函数而不是带有连接的查询(&lt; 1秒)

SELECT parm_TestConcatReferenceDatasetExposure.fldPurity, 
       Count(*) AS RcdCount
FROM parm_TestConcatReferenceDatasetExposure
GROUP BY parm_TestConcatReferenceDatasetExposure.fldPurity;

这是在一个表(&lt; 1秒)

上使用SQL部分近似函数的快速查询
SELECT tblTests.fldPurity, 
       IIf(IsNumeric(Replace(Replace(Nz(Trim([fldPurity]),""),"%",""),"+","")),CDbl(Replace(Replace(Trim([fldPurity]),"%",""),"+","")),Trim([fldPurity])) AS tempPurity, 
       Count(*) AS RcdCount
FROM tblTests
GROUP BY tblTests.fldPurity
ORDER BY IIf(IsNumeric(Replace(Replace(Nz(Trim([fldPurity]),""),"%",""),"+","")),CDbl(Replace(Replace(Trim([fldPurity]),"%",""),"+","")),Trim([fldPurity]));

以下是带连接的查询

SELECT q_Test.fldTestsID, q_DatasetTreatment.fldDatasetsID, 
       q_DatasetTreatment.fldExposureEffectsID, q_Test.fldValidated, 
       q_Test.fldPollutantID, q_Test.fldPollutantName, q_Test.fldPollutantCAS, 
       q_Test.fldModeOfActionID, q_Test.fldModeOfAction, q_Test.fldPollutantTypeID, 
       q_Test.fldPollutantType, q_Test.fldSpeciesID, q_Test.fldClass, q_Test.fldGenus,
       q_Test.fldSpecies, q_Test.fldCommonName, q_Test.fldTestTypeID, 
       q_Test.fldTestType, q_Test.fldTechniqueID, q_Test.fldTechnique,
       q_Test.fldConcUnits, q_Test.fldDescription AS fldConcUnitDescription,
       q_Test.fldMRID, q_Test.fldCETISID, q_Test.fldHardness, q_Test.fldSalinity, 
       q_Test.fldpH, q_Test.fldTemperature, q_Test.fldPurity, q_Test.fldDO, 
       q_Test.fldAcute, q_Test.fldUser, q_Test.fldComments, 
       IIf([q_sumTestReference].[fldTestsID] Is Not Null,[ConcatRef],"") AS CombinedRef, 
       q_DatasetTreatment.fldBiolVarNameID, q_DatasetTreatment.fldBiolVarName, 
       q_DatasetTreatment.fldLifeStageID, q_DatasetTreatment.fldLifeStage, 
       q_DatasetTreatment.fldDataTypeID, q_DatasetTreatment.fldDataType, 
       q_DatasetTreatment.fldGenerationID, q_DatasetTreatment.fldGeneration, 
       q_DatasetTreatment.fldEffectTypeID, q_DatasetTreatment.fldEffectType, 
       q_DatasetTreatment.fldDurationDays, q_DatasetTreatment.fldBVUnits, 
       q_DatasetTreatment.fldDescription AS fldBVUnitDescription, 
       q_DatasetTreatment.fldReportedNOEC, q_DatasetTreatment.fldReportedLOEC, 
       q_DatasetTreatment.fldTreatmentNum, q_DatasetTreatment.fldControlTypeID, 
       q_DatasetTreatment.fldControlType, q_DatasetTreatment.fldReplicateNum, 
       q_DatasetTreatment.fldPseudoReplicateNum, q_DatasetTreatment.fldNumberExposed,
       q_DatasetTreatment.fldMeasuredConcentration, 
       q_DatasetTreatment.fldNominalConcentration, q_DatasetTreatment.fldBiolVarValue
FROM q_sumTestReference 
RIGHT JOIN (q_Test 
            LEFT JOIN q_DatasetTreatment 
                   ON q_Test.fldTestsID = q_DatasetTreatment.fldTestsID) 
        ON q_sumTestReference.fldTestsID = q_Test.fldTestsID
ORDER BY q_Test.fldTestsID, q_DatasetTreatment.fldDatasetsID,
         q_DatasetTreatment.fldTreatmentNum, q_DatasetTreatment.fldReplicateNum;

我想使用该功能,因为它更简单,更清晰的代码。有什么建议?我在this post on SQL Server user-defined functions中看到它逐行评估。这是否意味着像我的第四个例子那样在SQL查询中的复杂解析语句是否正确?

1 个答案:

答案 0 :(得分:1)

@HansUp。谢谢,这很有效。这是工作查询。

SELECT parm_TestConcatReferenceDatasetExposure.fldPurity,
       Val(Replace(Replace(Nz(Trim([fldPurity]),""),"%",""),"+","")) AS temp5, 
       Count(*) AS RcdCount
FROM parm_TestConcatReferenceDatasetExposure
GROUP BY parm_TestConcatReferenceDatasetExposure.fldPurity, 
         Val(Replace(Replace(Nz(Trim([fldPurity]),""),"%",""),"+",""))
ORDER BY Val(Replace(Replace(Nz(Trim([fldPurity]),""),"%",""),"+",""));