码迷,mamicode.com
首页 > 数据库 > 详细

高级T-SQL进阶系列 (一)【下篇】:使用 CROSS JOIN 介绍高级T-SQL

时间:2019-11-04 22:01:57      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:最小化   tin   结果   问题   varchar   values   创建   有一个   ros   

【译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正】

性能考虑
产生了笛卡尔积的这个CROSS JOIN操作符具有一些性能方面的问题需要考虑。因为SQL引擎需要将一个数据集的每一行与另一个数据集的每一行进行关联,其结果集合将会非常巨大。如果我将一个具有 1,000,000行数据的表与另一张具有 1,000,000行数据的表进行CROSS JOIN,那么我的结果集将会包含 1,000,000* 1,000,000行数据,也就是100,000,000,000行数据。这是一个非常巨大结果集合并且它将占用SQL SERVER大量的时间来创建它。

CROSS JOIN操作符是一个其用来识别两个集合之间所有可能的组合的很好的解决方案,比如说是每个客户每个月所有的销售订单,甚至于在某几个月某些客户没有销售单。当使用CROSS JOIN操作符的时候,如果你想要优化性能,你应该试着最小化用来CROSS JOIN的集合的行数。举个例子,假设我有一个表包含了最近两个月的销售单,如果我要展示一个报告展示一个月内没有销售单的客户,那么识别一个月的日期数的方式可以改变我的查询的性能。为了演示这个我首先创建一个包含1000个客户在两个月之间的销售单集合,我会用列表7的代码来做这件事:

CREATE TABLE Cust (Id int, CustName varchar(20));
CREATE TABLE Sales (Id int identity
                    ,CustID int
                    ,SaleDate date
                    ,SalesAmt money);
SET NOCOUNT ON;
DECLARE @I int = 0;
DECLARE @Date date;
WHILE @I < 1000
BEGIN    
    SET @I = @I + 1;
    SET @Date = DATEADD(mm, -2, 2014-11-01);
    INSERT INTO Cust 
    VALUES (@I, 
            Customer # + right(cast(@I+100000 as varchar(6)),5));
    WHILE @Date < 2014-11-01 
    BEGIN
        IF @I%7 > 0
            INSERT INTO Sales (CustID, SaleDate, SalesAmt) 
            VALUES (@I, @Date, 10.00);
        SET @Date = DATEADD(DD, 1, @Date);
    END
END

列表7:用来创建性能测试数据示例的TSQL

列表7的代码为1000个不同的客户创建了2个月的数据。这段代码为每第七个用户不插入销售记录。这段代码为Cust表插入了1000条记录,并且为Sales 表插入了52,338 条记录。

为了演示使用CROSS JOIN操作符依赖于输入数据集大小会有如何的不同,让我们运行列表8和列表9的代码,对于每一个测试我会记录下它们返回结果所需要的时间。

SELECT CONVERT(CHAR(6),S1.SaleDate,112) AS SalesMonth, C.CustName, 
       ISNULL(SUM(S2.SalesAmt),0) AS TotalSales
FROM Cust C
CROSS JOIN  
(
SELECT SaleDate FROM Sales 
) AS S1
LEFT OUTER JOIN 
Sales  S2
ON C.ID = S2.CustID
AND S1.SaleDate = S2.SaleDate
GROUP BY CONVERT(CHAR(6),S1.SaleDate,112),C.CustName
HAVING ISNULL(SUM(S2.SalesAmt),0) = 0
ORDER BY CONVERT(CHAR(6),S1.SaleDate,112),C.CustName

列表8:所有记录的CROSS JOIN

SELECT CONVERT(CHAR(6),S1.SaleDate,112) AS SalesMonth, C.CustName, 
       ISNULL(SUM(S2.SalesAmt),0) AS TotalSales
FROM Cust C
CROSS JOIN  
(
SELECT DISTINCT SaleDate FROM Sales 
) AS S1
LEFT OUTER JOIN 
Sales  S2
ON C.ID = S2.CustID
AND S1.SaleDate = S2.SaleDate
GROUP BY CONVERT(CHAR(6),S1.SaleDate,112),C.CustName
HAVING ISNULL(SUM(S2.SalesAmt),0) = 0
ORDER BY CONVERT(CHAR(6),S1.SaleDate,112),C.CustName

列表9:去重销售日期记录的CROSS JOIN

在列表8中,CROSS JOIN操作符将1000条Cust表记录和52,338条Sales表记录进行关联用来产生52,338,000行的数据集合,这些记录随后用来决定在一个月中具有0条销售记录的客户。在列表9中,我改变了查询条件,从Sales表中仅仅返回SalesDate值的去重集合。这个去重的集合仅仅产生了61条不同的SalesDate值,因此列表9的CROSS JOIN操作符仅仅产生了61,000条记录。通过减少CROSS JOIN操作符的结果集,我的列表9的查询运行了少于1秒的时间,同时

高级T-SQL进阶系列 (一)【下篇】:使用 CROSS JOIN 介绍高级T-SQL

标签:最小化   tin   结果   问题   varchar   values   创建   有一个   ros   

原文地址:https://www.cnblogs.com/qianxingmu/p/11794884.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!