优化复杂的SQL查询

时间:2018-02-20 09:28:01

标签: sql-server azure-sql-database

我正在使用azure sql server数据库。我写了一个sql查询来生成reprot。这是:

<input type="text" class="form-control numOnly" onkeypress="return Validate(event);">

<script type="text/javascript">
    function Validate(event) {
        var regex = new RegExp("^[0-9-!@#$%*?,]");
        var key = String.fromCharCode(event.charCode ? event.which : event.charCode);
        if (!regex.test(key)) {
            event.preventDefault();
            return false;
        }
    }       
</script>

有没有办法优化此查询。超时问题来了。我在store过程中编写了这个查询,并使用linq实体框架调用该存储过程。

早些时候我使用了连接,但它更慢,所以尝试使用子查询。工作超过一年现在没有工作。

4 个答案:

答案 0 :(得分:1)

这肯定会提高性能,特别是如果表Approval.OrderDetail很大:

...WHERE not exists
(SELECT 1 from Approval.OrderDetail od WHERE od.ProjectID = cte.ProjectID)

答案 1 :(得分:1)

为每个字段编写一个子选择是一种检索数据的可怕方法,因为您可能最终会遇到大量的循环连接,这些连接在大型数据集上的性能很差。

您的原始JOIN方法是可行的方法,但您需要确保在加入列上有适当的索引。

您还可以使用WHERELEFT JOIN组合替换IS NULL子句

LEFT JOIN Approval.OrderDetail od
ON od.ProjectID = p.ProjectID
...
AND od.ProjectID IS NULL;

NOT EXISTS(尽管对于主查询返回的每一行,更可能需要扫描更广泛的行)。

WHERE NOT EXISTS 
(SELECT 1 FROM Approval.OrderDetail od WHERE od.ProjectID = cte.ProjectID)

在任何一种情况下,请确保您的Project表已在(IsBackgroundUsed, s7ImageGenerated, SiteCode, CreatedDate)上正确编入索引,并且所有联接都已正确编入索引。

我还质疑您是否确实需要将CreatedDateUTC字段投放到DATE类型?

可能的简化可能是:

SELECT
    p.ProjectID,
    p.CreatedDateUTC,
    b.BackgroundName,
    pr.Name,
    IIF(p.LicenseID IS NULL, 'Standard', l.LicenseName) AS CLA,
    pb.PurchaseFG,
    pr.FGCode AS ProductFGCode,
    '' AS ERPOrderNumber,
    0 AS DesignQuantity
FROM Project p
LEFT JOIN Approval.OrderDetail od
ON od.ProjectID = p.ProjectID
LEFT JOIN Background b
ON b.BackgroundID = p.BackgroundID
LEFT JOIN Product pr 
ON pr.ProductID = p.ProductID
LEFT JOIN License l
ON l.LicenseID = p.LicenseID
LEFT JOIN Product_Background pb
ON pb.BackgroundID = p.BackgroundID
AND pb.ProductID = p.ProductID
WHERE p.CreatedDateUTC >= @StartDate AND p.CreatedDateUTC <= @EndDate
  AND p.IsBackgroundUsed = 1
  AND p.s7ImageGenerated = 1 
  AND p.SiteCode = 'b2c'
  AND od.ProjectID IS NULL;

答案 2 :(得分:0)

WHERE  CAST(p.CreatedDateUTC AS DATE) >= @StartDate and CAST(p.CreatedDateUTC AS DATE) <= @EndDate 

制作此SARGAble,在CreatedDateUTC上创建非聚集索引

假设这是参数,

 declare @StartDate datetime='2018-02-01'
 declare @EndDate datetime='2018-02-28'

然后,

set @EndDate=dateadd(second,-1,dateadd(day,1,@EndDate))

现在你可以安全地使用这个,

WHERE  p.CreatedDateUTC  >= @StartDate and p.CreatedDateUTC  <= @EndDate 

我认为,@ Mark Sinkinson查询将比子查询更好。(我将尝试NOT EXISTS子句一次)

如果可能,请使用INNER JOIN。 希望您使用存储过程并调用SP。

在所有连接列上创建索引。

由于你的子查询在没有TOP 1的情况下工作正常,所以看起来所有表都与Project有一对一的关系。

CREATE NONCLUSTERED INDEX IX_Project ON project (
    CreatedDateUTC
    ,IsBackgroundUsed
    ,s7ImageGenerated
    ,SiteCode
    ) include (ProductID,LicenseID,BackgroundID);

希望projectID已经是Clustered Index。

答案 3 :(得分:0)

可能不会更快,但更容易为我阅读。

您应该能够调整@StartDate和@EndDate,而不必投射到目前为止。

拥有所有联接的索引和条件。

如果这些是FK,你应该能够使用内连接(并且应该)。

SELECT P.ProjectID , P.CreatedDateUTC,
       b.BackgroundName,
       pr.Name AS ProductName, 
       isnull(l.LicenseName, 'Standard') as CLA,
       pb.PurchaseFG,
       pr.FGcode AS ProductFGCode,
       '' AS ERPOrderNumber,
       0  AS DesignQuanity
 from Project p 
 left join Background b 
   on b.BackgroundID  = p.BackgroundID 
 left join Product pr
   on pr.ProductID    = p.ProductID 
 left join License l 
   on l.LicenseID     = p.LicenseID 
 left join Product_background pb 
   on pb.BackgroundID = p.BackgroundID 
  and pb.ProductId    = p.productID
 left join Product pr 
   on pr.ProductID    = p.ProductID
WHERE CAST(p.CreatedDateUTC AS DATE) >= @StartDate 
  and CAST(p.CreatedDateUTC AS DATE) <= @EndDate 
  and p.IsBackgroundUsed = 1
  and p.s7ImageGenerated = 1  
  and p.SiteCode = 'b2c'
  and not exists (SELECT 1 
                  from Approval.OrderDetail od 
                  WHERE od.ProjectID = p.ProjectID)