表变量和临时表之间的巨大性能差异

时间:2013-10-08 12:17:38

标签: sql-server-2008 tsql temp-tables table-variable

我有一个UDF,提供了大量数据。使用了几个表变量。目前,没有创建索引。

使用testdata的运行时大约 30秒

仅将表变量更改为临时表(UDF之外,因为不允许#tables),会显着降低运行时间。这是 3秒。 这个article解释了这些差异,但我没有看到这一点,它负责这种性能 - 增量。

无论如何 - UDF中不允许使用临时表,因此我可以轻松使用SPROC。不幸的是我不能,因为数据的目标“容器”必须是视图或表。由于第三方限制,不可更改。 (erp系统的数据是预先处理的,必须在表格或视图中提供,例如您可以通过select <col> from <object>访问的任何内容。

我尝试添加一个索引来创建目前使用的表变量,但运行时没有减少。

在最后将数据导入视图时,可以获得任何有关临时表性能的提示或技巧。

SQL-Query(添加了表变量,但无法提供演示数据):

declare  @Results TABLE
(
          "id"                  NVARCHAR( 100 )
        , "oprNum1"             INT
        , "job1Id"              NVARCHAR( 100 )
        , "job1Type"            INT
        , "oprNum2"             INT
        , "job2Id"              NVARCHAR( 100 )
        , "job2Type"            INT
        , "minimumDistance"     INT
        , "maximumDistance"     INT
        , "resourceLocked"      INT
        , "durationLocked"      INT
        , "slot1"               FLOAT
        , "slot2"               FLOAT
        , "color"               BIGINT
        , "origin"              NVARCHAR( 50 )
        , "partition"           BIGINT 
)

    DECLARE @jobs TABLE
    (  
        "rank"              INT
        , "id"              NVARCHAR( 100 )
        , "projectId"       NVARCHAR( 100 )
        , "prodId"          NVARCHAR( 20 )
        , "oprNum"          INT
        , "oprPriority"     INT
        , "jobId"           NVARCHAR( 100 )
        , "jobType"         INT
        , "overlapFactor"   FLOAT
        , "partition"       BIGINT

        , UNIQUE CLUSTERED("rank","prodId","jobid")
    );

    INSERT INTO @jobs
    SELECT
        "rank"              = RANK() OVER ( PARTITION BY job."dataAreaId", job."prodId"
                                    , CASE job."oprPriority"
                                        WHEN 0 THEN job."oprPriority" 
                                        ELSE job."oprPriority" / job."oprPriority" 
                                    END
                                ORDER BY job."rank" )
        , "id"              = job."id"
        , "projectId"       = job."projectId"
        , "prodId"          = job."prodId"
        , "oprNum"          = job."oprNum"
        , "oprPriority"     = job."oprPriority"
        , "jobId"           = job."axJobId"
        , "jobType"         = job."jobType"
        , "overlapFactor"   = job."overlapFactor"
        , "partition" = job."partition"
    FROM "dbo"."_company_job" AS job;

    INSERT INTO @Results
    (
          "id"
        , "oprNum1"
        , "job1Id"
        , "job1Type"
        , "oprNum2"
        , "job2Id"
        , "job2Type"
        , "minimumDistance"
        , "maximumDistance"
        , "resourceLocked"
        , "durationLocked"
        , "slot1"
        , "slot2"
        , "color"
        , "origin"
        , "partition"
    )
    SELECT DISTINCT     
          "id"              = Job1."id" + N'_' + Job2."id"
        , "oprNum1"         = Job1."oprNum"
        , "job1Id"          = Job1."id"
        , "job1Type"        = Job1."jobType"
        , "oprNum2"         = Job2."oprNum"
        , "job2Id"          = Job2."id"
        , "job2Type"        = Job2."jobType"
        , "minimumDistance" = 0
        , "maximumDistance" = 0
        , "resourceLocked"  = CASE Job1."oprNum" WHEN Job2."oprNum" THEN 1 ELSE 0 END
        , "durationLocked"  = 0
        , "slot1"           = Job1."OVERLAPFACTOR"
        , "slot2"           = 0.0
        , "color"           = 0x00FFFFFF
        , "origin"          = 'job'
        , "partition" = Job1."partition"
    FROM @jobs AS Job1
    INNER JOIN @jobs AS Job2
        ON 1 = 1
        AND Job2."partition" = Job1."partition"
        AND Job2."projectId"        = Job1."projectId"
        AND Job2."oprPriority"  = Job1."oprPriority"
        AND Job2."rank"         = Job1."rank" +1
        AND Job2."id"           != Job1."id"
        AND Job2.jobType        NOT IN ( 4 )
    WHERE Job1."oprPriority" = 0
        OR ( Job1."oprPriority" > 0 AND Job1."oprNum" = job2."oprNum" );

    INSERT INTO @Results
    (
          "id"
        , "oprNum1"
        , "job1Id"
        , "job1Type"
        , "oprNum2"
        , "job2Id"
        , "job2Type"
        , "minimumDistance"
        , "maximumDistance"
        , "resourceLocked"
        , "durationLocked"
        , "slot1"
        , "slot2"
        , "color"
        , "origin"
        , "partition"
    )
    SELECT
          "id"              = Job1."id" + N'_' + Job2."id"
        , "oprNum1"         = Job1."oprNum"
        , "job1Id"          = Job1."id"
        , "job1Type"        = Job1."jobType"
        , "oprNum2"         = Job2."oprNum"
        , "job2Id"          = Job2."id"
        , "job2Type"        = Job2."jobType"
        , "minimumDistance" = 0
        , "maximumDistance" = 2147483647
        , "resourceLocked"  = CASE Job1."oprNum" WHEN Job2."oprNum" THEN 1 ELSE 0 END
        , "durationLocked"  = 0
        , "slot1"           = job2."OVERLAPFACTOR"
        , "slot2"           = 0.0
        , "color"           = 0x000000FF    
        , "origin"          = 'milestone'
        , "partition"       = Job1."partition"
    FROM @jobs AS job1
    INNER JOIN @jobs AS job2
    ON 1 = 1
    AND job2."partition" = job1."partition"
    AND job2."projectId"        = job1."projectId"
        AND Job2."oprPriority"  = Job1."oprPriority"
        AND Job2."rank"         = Job1."rank" +1
        AND Job1."id"           != Job2."id"
        AND Job2.jobType        IN ( 4 );

    INSERT INTO @Results
    (
          "id"
        , "oprNum1"
        , "job1Id"
        , "job1Type"
        , "oprNum2"
        , "job2Id"
        , "job2Type"
        , "minimumDistance"
        , "maximumDistance"
        , "resourceLocked"
        , "durationLocked"
        , "slot1"
        , "slot2"
        , "color"
        , "origin"
        , "partition"
    )
    SELECT
        "id"                = CASE slot."value" 
                                WHEN 0.0
                                    THEN Job1."id" + N'_' + Job2."id"
                                ELSE Job2."id" + N'_' + Job1."id"
                            END
        , "oprNum1"         = Job1."oprNum"
        , "job1Id"          = Job1."id"
        , "job1Type"        = Job1."jobType"
        , "oprNum2"         = Job2."oprNum"
        , "job2Id"          = Job2."id"
        , "job2Type"        = Job2."jobType"
        , "minimumDistance" = 0
        , "maximumDistance" = 0
        , "resourceLocked"  = 0
        , "durationLocked"  = 0
        , "slot1"           = slot."value"
        , "slot2"           = slot."value"
        , "color"           = 0xCCCC00FF
        , "origin"          = N'job'
        , "partition" = Job1."partition"
    FROM @jobs AS Job1
    INNER JOIN @jobs AS Job2
        ON 1 = 1
        AND job2."partition" = job1."partition"
        and  job2."projectId"       = job1."projectId"
        AND job2."oprNum"       = job1."oprNum"
        AND job2."jobType"      = job1."jobType"
        AND Job2."oprPriority"  = job1."oprPriority" +1
        AND Job2."id"           != Job1."id"
    LEFT JOIN @jobs AS prevJob
        ON 1 = 1
        AND prevJob."partition" = job2."partition" 
        AND prevJob."projectId"     =   job2."projectId"
        AND prevJob."rank"          =   job2."rank" -1
        AND prevJob."oprPriority"   =   job2."oprPriority"
        AND prevJob."id"            !=  job2."id"
    INNER JOIN "dbo"."BASEENUMS" AS enums
        ON enums."NAME" = N'someName'
        AND job1."jobType" = enums."VALUEID"
    INNER JOIN ( 
        select 0.0 as "value"
        union all 
        select 1.0 
    ) as slot
        ON ( slot."value" = 0 AND ( enums."VALUE" = N'setup' OR ( enums."VALUE" = N'normal' AND prevJob."id" IS NULL ) ) )
        OR ( slot."value" = 1 AND enums."VALUE" = N'normal' );

    DECLARE @PeggingRelations TABLE
    (
            "oprNum1"               INTEGER
            , "job1Id"              NVARCHAR( 100 )
            , "job1Type"            INT
            , "oprNum2"             INTEGER
            , "job2Id"              NVARCHAR( 100 )
            , "job2Type"            INT
            , "minimumDistance"     INT
            , "maximumDistance"     INT
            , "resourceLocked"      INT
            , "durationLocked"      INT
            , "slot1"               FLOAT
            , "slot2"               FLOAT
            , "color"               INT     
            , "origin"              NVARCHAR(50)
            , "partition" BIGINT
    );

    DECLARE @MinMax TABLE
    (
          "prodId"      NVARCHAR( 20 )
        , "maxOprNum"   INT
        , "minOprNum"   INT
    );

    INSERT INTO @MinMax
    SELECT 
          "prodId"      = "prodId"
        , "maxOprNum"   = MAX( "oprNum" ) 
        , "minOprNum"   = MIN( "oprNum" ) 
    FROM
        "dbo"."_company_job"
    GROUP BY 
          "prodId";

    INSERT INTO @PeggingRelations
    SELECT DISTINCT
        "oprNum1"           = Job1."oprNum"
        , "job1Id"          = Job1."id"
        , "job1Type"        = Job1."jobType"
        , "oprNum2"         = Job2."oprNum"
        , "job2Id"          = Job2."id"
        , "job2Type"        = Job2."jobType"
        , "minimumDistance" = 0
        , "maximumDistance" = 2147483647
        , "resourceLocked"  = CASE Job1."oprNum" WHEN Job2."oprNum" THEN 1 ELSE 0 END
        , "durationLocked"  = 0
        , "slot1"           = job1."OVERLAPFACTOR"
        , "slot2"           = 0.0
        , "color"           = 0x0000FFFF    
        , "origin"          = N'workorder'
        , "partition"       = Job1."partition"
    FROM
        "dbo"."REQTRANSCOV" AS Link
    INNER merge JOIN "dbo"."REQTRANS" AS Issuer
         ON Issuer."DATAAREAID"     = Link."DATAAREAID"
         AND Issuer."PARTITION" = Link."PARTITION"  
        AND Issuer."RECID"          = Link."ISSUERECID"
    INNER JOIN "dbo"."REQTRANS" AS Receiver
         ON Receiver."DATAAREAID"   = Link."DATAAREAID"
         AND Receiver."partition" = Link."partition"
        AND Receiver."recid"        = Link."RECEIPTRECID"
    INNER JOIN @MinMax AS IssuerMinOprNum
         ON IssuerMinOprNum."PRODID"        = Issuer."REFID"
    INNER JOIN @MinMax AS ReceiverMaxOprNum
         ON ReceiverMaxOprNum."PRODID"      = Receiver."REFID"
    INNER JOIN "dbo"."_company_job" AS Job2 
         ON Job2."prodId"           = Issuer."REFID"
        AND Job2."oprNum"           = IssuerMinOprNum."minOprNum"
        AND Job2."isFirst"      = 1
        AND Job2."oprPriority"  = 0
        AND Job2."partition" = Issuer."partition"
    INNER JOIN "dbo"."_company_job" AS Job1
         ON Job1."prodId"       = Receiver."REFID"
        AND Job1."isLast"       = 1
        AND Job1."sourceTable"  = N'PRODTABLE'
        and job1."partition" = Receiver."partition"
    WHERE  
        1 = 1
        AND Issuer."REFTYPE"    IN ( 9, 12 )
        AND Receiver."REFTYPE"  IN ( 9, 12 )
        AND Link."DATAAREAID" = N'company'

    INSERT INTO @Results
    (
          "id"
        , "oprNum1"
        , "job1Id"
        , "job1Type"
        , "oprNum2"
        , "job2Id"
        , "job2Type"
        , "minimumDistance"
        , "maximumDistance"
        , "resourceLocked"
        , "durationLocked"
        , "slot1"
        , "slot2"
        , "color"
        , "origin"      
        , "partition"
    )
    SELECT
          "id"              = "job1Id" + N'_' + "job2Id"
        , "oprNum1"
        , "job1Id"  
        , "job1Type"
        , "oprNum2"
        , "job2Id"  
        , "job2Type"        
        , "minimumDistance"
        , "maximumDistance"
        , "resourceLocked"
        , "durationLocked"
        , "slot1"
        , "slot2"
        , "color"
        , "origin"
        , "partition"
    FROM
        @PeggingRelations;

    INSERT INTO @Results 
    (
          "id"
        , "oprNum1"
        , "job1Id"
        , "job1Type"
        , "oprNum2"
        , "job2Id"
        , "job2Type"
        , "minimumDistance"
        , "maximumDistance"
        , "resourceLocked"
        , "durationLocked"
        , "slot1"
        , "slot2"
        , "color"
        , "origin"
        , "partition"
    )
    SELECT
          "id"              = Job1."id" + N'_' + Job2."id"
        , "oprNum1"         = Job1."oprNum"
        , "job1Id"          = Job1."id"
        , "job1Type"        = Job1."jobType"
        , "oprNum2"         = Job2."oprNum"
        , "job2Id"          = Job2."id"
        , "job2Type"        = Job2."jobType"
        , "minimumDistance" = 0
        , "maximumDistance" = 2147483647
        , "resourceLocked"  = CASE Job1."oprNum" WHEN Job2."oprNum" THEN 1 ELSE 0 END
        , "durationLocked"  = 0
        , "slot1"           = job1."OVERLAPFACTOR"
        , "slot2"           = 0.0
        , "color"           = 0x0000FFFF    
        , "origin"          = N'workorder'
        , "partition"       = Job1."partition"
    FROM 
        "dbo"."PRODBOM" AS PB
    INNER JOIN "dbo"."_company_job" AS Job1
         ON Job1."prodId"       = PB."INVENTREFID"
         and Job1."partition" = PB."partition"
        AND Job1."isLast"       = 1
        AND Job1."sourceTable"  = N'PRODTABLE'
        AND Job1."jobType"      = 4
    INNER JOIN "dbo"."_company_job" AS Job2
         ON Job2."prodId"       = PB."PRODID"
        AND Job2."oprNum"       = PB."OPRNUM"
        AND Job2."isFirst"      = 1
        and Job2."partition" = PB."partition"
    LEFT OUTER JOIN @Results AS Rel
         ON Rel."job1Id"    = Job1."id"
        AND Rel."job2Id"    = Job2."id"
        AND Rel."slot1"     = job1."OVERLAPFACTOR"
        AND Rel."slot2"     = 0.0
        AND Rel."partition" = Job1."partition"
    WHERE 
        1 = 1
        AND PB."DATAAREAID" = N'company'
        AND PB."INVENTREFTYPE"  = 3
        AND Rel."Id" IS NULL
        AND Rel."partition" = Job1."partition";

0 个答案:

没有答案