为什么使用用户定义函数的查询比具有多个连接(包括外部连接)的查询慢?该函数的原因是修改一个字符串,使其按数字排序。对字符串进行排序意味着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]);
这是没有功能的快速查询,而不是带连接的查询(<1 秒)
SELECT parm_TestConcatReferenceDatasetExposure.fldPurity,
Count(*) AS RcdCount
FROM parm_TestConcatReferenceDatasetExposure
GROUP BY parm_TestConcatReferenceDatasetExposure.fldPurity;
这是在一张表上使用 SQL 部分近似函数的快速查询(<1 秒)
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;
我想使用该函数,因为它更简单、更清晰的代码。有什么建议么?我在这篇关于 SQL Server 用户定义函数的帖子中看到它逐行计算。这是否意味着像我的第四个示例这样的 SQL 查询中的复杂解析语句是正确的?