【问题标题】:use udf in sql vs method in C# code in performance在 sql 中使用 udf 与 C# 代码中的方法在性能方面
【发布时间】:2019-11-23 11:04:51
【问题描述】:

听到的是我在验证代码中的用户定义函数人员代码分配... 时间分配中的每个人员在时间表程序中的卡号。运行疏散服务时,计时员信息发送到此功能以验证人员。 功能在只有 1 个人员分配到此卡时返回有效人员。

ALTER FUNCTION [dbo].[GetPerosnnleBaseIdByCardAndTime]( @Card VARCHAR(100),@Time SMALLDATETIME)
RETURNS INT
AS
BEGIN
----------------
--DECLARE @Card VARCHAR(100) = '11000'
--DECLARE @Time SMALLDATETIME = '2019-02-01 00:00:00'--GETDATE()
---------------------------------
DECLARE @MaxDate SMALLDATETIME
DECLARE @PersonnelBaseId INT
DECLARE @Current int = 0
SELECT 
    @MaxDate = MAX(EffectiveDate) 
FROM 
    dbo.tkp_PersonnelDetails records
    inner join prs_Personnel personnel on personnel.Id = records.PersonnelBaseID AND    
                                                         Personnel.Active = 1    AND 
                                                         Personnel.Deleted = 0   AND
                                                         records.Deleted = 0    
WHERE records.Deleted = 0 AND records.EffectiveDate <= @Time AND CardNo = @Card

SELECT @PersonnelBaseId = PersonnelBaseId, @Current = [Current] FROM dbo.tkp_PersonnelDetails WHERE EffectiveDate = @MaxDate AND Deleted = 0 AND CardNo = @Card 

IF ((SELECT COUNT(*) FROM dbo.tkp_PersonnelDetails WHERE CardNo = @Card AND EffectiveDate <= @Time AND Deleted = 0) = 1)
    RETURN @PersonnelBaseId
--IF @Current = 1 
--  SELECT @PersonnelBaseId
---------
DECLARE @DETAILS TABLE (PersonnelBaseId INT,CardNo VARCHAR(100),EffectiveDate SMALLDATETIME,ROW_NO INT,PERS_NNUMBER INT)
INSERT INTO @DETAILS
SELECT 
     PD.PersonnelBaseId,CardNo,EffectiveDate        
    ,ROW_NUMBER() OVER(PARTITION BY PD.PERSONNELBASEID ORDER BY EFFECTIVEDATE) AS ROW_NO
    ,DENSE_RANK() over(ORDER BY PD.PERSONNELBASEID) AS PERS_NNUMBER 
FROM
    dbo.tkp_PersonnelDetails PD 
WHERE PersonnelBaseId in (select PersonnelBaseId from dbo.tkp_PersonnelDetails where CardNo = @Card)
ORDER BY 
    PERS_NNUMBER,ROW_NO
DECLARE @CurrectPersonnelCount int = 0
DECLARE @MaxPersNumber int = 1,@MaxRowNumber int = 1
DECLARE @PersNumber int = 1,@RowNumber int = 1
DECLARE @_PersonnelBaseId int ,@_CardNo varchar(100) ,@_EffectiveDate smalldatetime,@_CardNoNext varchar(100) ,@_EffectiveDateNext smalldatetime

SELECT @MaxPersNumber = max(PERS_NNUMBER) FROM @DETAILS
WHILE @PersNumber <= @MaxPersNumber
BEGIN
    SELECT @_PersonnelBaseId = PersonnelBaseId,@_CardNo = CardNo,@_EffectiveDate = EffectiveDate FROM @DETAILS WHERE PERS_NNUMBER = @PersNumber AND ROW_NO = @RowNumber
    SELECT @MaxRowNumber = max(ROW_NO) FROM @DETAILS WHERE PersonnelBaseId = @_PersonnelBaseId
    WHILE @RowNumber <= @MaxRowNumber
    BEGIN
        IF @_CardNo = @Card and @_EffectiveDate <= @Time
        BEGIN
            SELECT @_CardNoNext = CardNo,@_EffectiveDateNext = EffectiveDate FROM @DETAILS WHERE PERS_NNUMBER = @PersNumber AND ROW_NO = @RowNumber +1          
            IF @_EffectiveDateNext > @Time OR @_EffectiveDateNext IS NULL
            BEGIN
                SET @CurrectPersonnelCount += 1
                SET @PersonnelBaseId = @_PersonnelBaseId
            END                         
        END
        SET @RowNumber += 1
        SELECT @_PersonnelBaseId = PersonnelBaseId,@_CardNo = CardNo,@_EffectiveDate = EffectiveDate FROM @DETAILS WHERE PERS_NNUMBER = @PersNumber AND ROW_NO = @RowNumber
    END
    SET @PersNumber += 1
END
IF @CurrectPersonnelCount = 1
    RETURN @PersonnelBaseId
ELSE 
    RETURN 0

--SELECT * FROM @DETAILS

RETURN 0
END

我可以用 C# 编写这个函数,但想知道哪个是最佳实践? 在 C# 方法或 中的“用户定义函数”中使用? 适用于大数据和小数据

【问题讨论】:

  • 如果您要在 SQL Server 中使用用户定义的函数,请使用内联表值函数;众所周知,标量和多行表值函数都表现不佳。但是,如果您使用的是 SQL Server 2019,则可以利用内联标量函数功能。
  • 为什么不在单独的表中使用映射 Personnel-Card-no?
  • 另外,WHILE 循环对于任何 SQL 来说都是一个非常糟糕的主意。除非您真的需要迭代任务(其中很少有场景)。您真的想使用基于集合的方法。
  • @Larnu 你的意思是如果我使用 SQL Server 2019 那么它不是在 .net 中吗?而且这个问题不依赖于数据规模?
  • 那不是我说的@abbasezoji,不。我说如果您使用 SQL Server,而不是“使用 SQL Server 2019”(仍处于预览阶段)。无论如何,您将无法将上述内容转换为内联标量函数。

标签: c# sql-server bigdata performance-testing


【解决方案1】:

你经常使用迭代函数,所以在这种情况下你不能使用内联函数,那么根据这个问题最好用C#方法处理函数。

【讨论】:

  • 老实说,这很模糊。这里没有足够的数据来说明 OP 在应用程序中的最佳性能。是的,迭代在应用程序中更好,但如果您在 DBMS 中执行逻辑,则不应从迭代开始,而应使用数据集方法。
【解决方案2】:

根据顶级证词,我尝试使用内联函数。 然后CTE创建的这个函数:

;WITH PersonnelDetailsByCarnoAndLessTime AS
(
    SELECT
        PD.*    
    FROM
        tkp_PersonnelDetails PD     
        JOIN prs_Personnel P ON P.ID = PersonnelBaseId AND P.DELETED = 0 AND P.ACTIVE = 1   
        JOIN (SELECT PersonnelBaseId,MAX(EffectiveDate) MAX_EffectiveDate
                FROM tkp_PersonnelDetails PD
                WHERE EffectiveDate <= @Time
                GROUP BY PersonnelBaseId
        ) T ON PD.PersonnelBaseId = T.PersonnelBaseId AND PD.EffectiveDate = T.MAX_EffectiveDate
    WHERE PD.Deleted = 0
), R AS
(
    SELECT 
        *
    FROM 
        PersonnelDetailsByCarnoAndLessTime PDL
    WHERE CardNo = @Card

), AssignmentCount AS
(
    SELECT
        MIN(PersonnelBaseId) PersonnelBaseId,
        COUNT((CASE WHEN EffectiveDate < @Time THEN 0 ELSE 1 END)) AssignmentCount
    FROM 
        R
)
SELECT CASE WHEN AssignmentCount = 1 THEN PersonnelBaseId ELSE 0 END PersonnelBaseId FROM AssignmentCount

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-17
    • 1970-01-01
    • 2011-01-31
    相关资源
    最近更新 更多