2013-08-07 43 views
1

爲什麼查詢使用用戶定義的函數通過包含外連接的多個連接的查詢變慢?該函數的原因是修改一個字符串,以便按數字排序。排序字符串意味着100 < 99。函數重新格式99 as 099。所以,099 < 100。它允許其他非數字值保持不變。訪問2007年用戶定義的函數加入緩慢

問題查詢使用函數通過帶連接的查詢。返回100行需要27秒。具有函數但是在一個表上的查詢需要亞秒。用查詢加入查詢的SQL替換是亞秒。沒有函數的查詢與連接的查詢是亞秒。主表是517行的tblTests。函數操作的列是文本列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 

在這裏是使用功能對查詢慢查詢與使用函數在一個表(< 1秒)

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

這裏快速查詢連接(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 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; 

我想使用的功能如它更簡單,代碼更簡潔。有什麼建議麼?我在this post on SQL Server user-defined functions看到它逐行評估。這是否意味着SQL查詢中的複雜解析語句就像我的第4個示例是正確的?

+1

如果您有一個包含數字的字符串,請使用'Val(your_string)'使它按數字順序排序。我不確定你需要一個UDF,而內建的'Val()'函數可以使查詢更快。 – HansUp

回答

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]),""),"%",""),"+",""));