Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SQL Server 2008 R2:透视表查询性能_Sql_Sql Server_Sql Server 2008 R2_Pivot - Fatal编程技术网

SQL Server 2008 R2:透视表查询性能

SQL Server 2008 R2:透视表查询性能,sql,sql-server,sql-server-2008-r2,pivot,Sql,Sql Server,Sql Server 2008 R2,Pivot,表:产品 插入: 第一次尝试:在这个例子中,我得到了错误的productType和 SELECT productID, FirstSale,LastSale, [Electronic],[books],[Vehicle] FROM ( SELECT productID, MIN(ProductSalesdate) as FirstSale, MAX(ProductSalesdate) as LastSale, produ

表:产品

插入:

第一次尝试:在这个例子中,我得到了错误的productType和

SELECT productID, FirstSale,LastSale, [Electronic],[books],[Vehicle]
FROM
(
    SELECT 
        productID, 
        MIN(ProductSalesdate) as FirstSale,
        MAX(ProductSalesdate) as LastSale,
        productType
    FROM
        Product
    Group by productID,productType
) a 
PIVOT
(
    COUNT(productType) 
    FOR productType IN ( [Electronic],[books],[Vehicle] )
) AS pvt;   
第二次尝试:在这次尝试中,我已经解决了求和问题,但是查询需要更多的时间来执行巨大的记录

SELECT productID,FirstSale,LastSale ,[Electronic],[books],[Vehicle]
FROM
(
    SELECT a.ProductID, a.FirstSale, a.LastSale, b.ProductType
    FROM Product b
    inner join
    (
        SELECT 
            productID, 
            MIN(ProductSalesdate) as FirstSale,
            MAX(ProductSalesdate) as LastSale
        FROM
            Product
        Group by productID
    ) as a 
    ON a.ProductID = b.ProductID
) ab 
PIVOT
(
    COUNT(productType) 
    FOR productType IN ( [Electronic],[books],[Vehicle] )
) AS pvt;   
注意:第二个查询工作正常,但问题在于性能,因为 我连接两个相同的表,因为我想在pivot查询中获取productType的计数


问题:如何优化我第二次尝试的第二个查询?

下面使用一个临时表来存储派生表ab。我猜这将改进第二个查询的执行计划

SELECT a.ProductID, a.FirstSale, a.LastSale, b.ProductType
INTO #ab
FROM Product b
inner join
(
    SELECT 
        productID, 
        MIN(ProductSalesdate) as FirstSale,
        MAX(ProductSalesdate) as LastSale
    FROM
        Product
    Group by productID
) as a 
ON a.ProductID = b.ProductID;

SELECT productID,FirstSale,LastSale ,[Electronic],[books],[Vehicle]
FROM #ab AS ab 
PIVOT
(
    COUNT(productType) 
    FOR productType IN ( [Electronic],[books],[Vehicle] )
) AS pvt;

DROP TABLE #ab;
编辑:只是为了体育,我写了下面的脚本,在产品中有15k行。整个脚本在~1秒内执行。我还是不明白你的查询怎么需要5.5分钟。下面是:

SET NOCOUNT ON;

CREATE TABLE #product (
    product_id INT,
    product_name VARCHAR(20),
    product_sales_date DATE,
    product_type VARCHAR(20)
);

DECLARE @cnt INT=0;
WHILE @cnt<15000
BEGIN
    INSERT INTO #product(
        product_id,
        product_name,
        product_sales_date,
        product_type
    )
    SELECT 
        product_id=ROUND(20*RAND(),0),
        product_name=LEFT(NEWID(),20),
        product_sales_date=DATEADD(DAY,ROUND((-10+20*RAND()), 0),GETDATE()),
        product_type=
            CASE ROUND(2*RAND(),0)
                WHEN 0 THEN 'Electronic'
                WHEN 1 THEN 'books'
                ELSE 'Vehicle'
            END;

    SET @cnt=@cnt+1;
END

SELECT a.product_id, a.first_sale, a.last_sale, b.product_type
INTO #ab
FROM #product b
inner join
(
    SELECT 
        product_id, 
        MIN(product_sales_date) as first_sale,
        MAX(product_sales_date) as last_sale
    FROM
        #product
    GROUP BY
        product_id
) as a 
ON a.product_id= b.product_id;

SELECT product_id,first_sale,last_sale,[Electronic],[books],[Vehicle]
FROM #ab AS ab 
PIVOT
(
    COUNT(product_type) 
    FOR product_type IN ( [Electronic],[books],[Vehicle] )
) AS pvt;

DROP TABLE #ab;
DROP TABLE #product;

好像你想做这样的事。。不确定为什么需要额外的联接或临时表

SELECT * FROM
(
    SELECT  productID, 
            productType,
            MIN(ProductSalesdate) as FirstSale,
            MAX(ProductSalesdate) as LastSale,
            COUNT(productType) AS ProductCount
    FROM Product
    GROUP BY productID,productType
) t
PIVOT 
(
    SUM(ProductCount)
    FOR productType IN ([Electronic],[books],[Vehicle])
) p

您将获得0计数的空值,但您可以很容易地将这些值合并为0

某个productType的产品是否具有相同的productId?此外,您在第二次尝试中有一个派生表a,它在productType、productId上分组,但您仅在productId上与b联接。。。你声称你的表现有问题。你能描述一下吗?需要几秒钟,几分钟,几小时?您期望的执行时间是多少?另外,表Product上是否有适当的索引?@TT,对于15k记录,似乎有10分钟的时间,是的,我在productID上有索引。现在是5.5分钟。这对我来说意义重大。@MAK Ouch这仍然很多。也许您可以在临时表上放置适当的键/索引?这要求您首先创建临时表并在其上添加索引,就像在常规表上创建和添加索引一样。然后第一个语句将变成INSERT到ab…cols。。。选择例如,如果不使用INTO ab.@MAK,您可以在SSMS中分析实际执行计划,请单击工具栏中的“包含实际执行计划”按钮。看看它是否提出了任何索引。@MAK在我的答案中添加了一个测试脚本,有15k行,相同的pivot查询在1秒内运行。嘿,非常感谢!OP的PIVOT查询存在性能问题,这就是为什么我建议首先将派生表具体化为临时表。很可能是您的版本做得更好。@TT。从我最近在这里注意到的情况来看,pivot本身存在性能问题,最好将这些丑陋的聚合与case语句结合使用。我可以向您介绍这样一个例子,其中一个表现不佳的PIVOT使用了老式PIVOT用例和OPTIONHASH GROUP的组合进行了优化,以加快分组速度。
SET NOCOUNT ON;

CREATE TABLE #product (
    product_id INT,
    product_name VARCHAR(20),
    product_sales_date DATE,
    product_type VARCHAR(20)
);

DECLARE @cnt INT=0;
WHILE @cnt<15000
BEGIN
    INSERT INTO #product(
        product_id,
        product_name,
        product_sales_date,
        product_type
    )
    SELECT 
        product_id=ROUND(20*RAND(),0),
        product_name=LEFT(NEWID(),20),
        product_sales_date=DATEADD(DAY,ROUND((-10+20*RAND()), 0),GETDATE()),
        product_type=
            CASE ROUND(2*RAND(),0)
                WHEN 0 THEN 'Electronic'
                WHEN 1 THEN 'books'
                ELSE 'Vehicle'
            END;

    SET @cnt=@cnt+1;
END

SELECT a.product_id, a.first_sale, a.last_sale, b.product_type
INTO #ab
FROM #product b
inner join
(
    SELECT 
        product_id, 
        MIN(product_sales_date) as first_sale,
        MAX(product_sales_date) as last_sale
    FROM
        #product
    GROUP BY
        product_id
) as a 
ON a.product_id= b.product_id;

SELECT product_id,first_sale,last_sale,[Electronic],[books],[Vehicle]
FROM #ab AS ab 
PIVOT
(
    COUNT(product_type) 
    FOR product_type IN ( [Electronic],[books],[Vehicle] )
) AS pvt;

DROP TABLE #ab;
DROP TABLE #product;
SELECT * FROM
(
    SELECT  productID, 
            productType,
            MIN(ProductSalesdate) as FirstSale,
            MAX(ProductSalesdate) as LastSale,
            COUNT(productType) AS ProductCount
    FROM Product
    GROUP BY productID,productType
) t
PIVOT 
(
    SUM(ProductCount)
    FOR productType IN ([Electronic],[books],[Vehicle])
) p