为什么我的SQL查询在一个数据库中这么慢?

时间:2015-06-11 09:25:39

标签: sql sql-server

我使用的是sql server 2008 r2,我有两个数据库,一个有11.000个记录,另一个只有3000个记录,当我运行这个查询时

SELECT Right(rtrim(tbltransac.No_Faktur),6) as NoUrut,
       tbltransac.No_Faktur,
       tbltransac.No_FakturP,
       tbltransac.Kd_Plg,
       Tblcust.Nm_Plg,
       GRANDTOTAL AS Total_Faktur,
       tbltransac.Nm_Pajak,
       tbltransac.Tgl_Faktur,
       tbltransac.Tgl_FakturP,
       tbltransac.Total_Distribusi 
FROM Tblcust
  INNER JOIN ViewGrandtotal AS tbltransac ON Tblcust.Kd_Plg = tbltransac.Kd_Plg 
WHERE tbltransac.Kd_Trn = 'J'
  and year(tbltransac.tgl_faktur)=2015
  And ISNULL(tbltransac.No_OPJ,'') <> 'SHOP'  
Order by Right(rtrim(tbltransac.No_Faktur),6) Desc

我的服务器(我使用sql管理工具查询)需要1分30秒才能获得3000条记录,但在我的另一台服务器上只需要3秒钟就可以查询11000条记录,我的服务器是什么数据库?

我已经尝试备份和恢复我的3000记录数据库并将其恢复到我的11000记录服务器中,它更快..花了30秒进行查询,但如果我与我的11000记录服务器相比仍然很烦人。它们属于同一规范

这是怎么发生的?我应该检查什么?我检查事件查看器,资源监视器或SQL管理日志,我找不到任何错误或阻止连接。也没有错误的路由..

请帮助......它发生在一周前,在此之前很好,而且我已经超过一个月没有触摸服务器......

3 个答案:

答案 0 :(得分:1)

注意: 首先,您应该避免 Where子句中的任何功能

year(tbltransac.tgl_faktur)=2015

Here Aaron Bertrand 如何在 Where子句中使用日期

“为了尽可能最好地使用索引,并避免捕获太少或太多行,实现上述查询的最佳方法是”:

SELECT COUNT(*)
      FROM dbo.SomeLogTable
      WHERE DateColumn >= '20091011'
      AND DateColumn < '20091012';

我无法理解你在这段代码中的逻辑,但这也是你查询的重要部分

ISNULL(tbltransac.No_OPJ,'') <> 'SHOP' 

在这种情况下实际上是Null <> "Shop",那么为什么要将其替换为""

谢谢,祝你好运

答案 1 :(得分:1)

以下是一些建议:

  1. year(tbltransac.tgl_faktur)=2015将此替换为tbltransac.tgl_faktur >= '20150101' and tbltransac.tgl_faktur < '20160101'

  2. ISNULL(tbltransac.No_OPJ,'') <> 'SHOP'将其替换为tbltransac.No_OPJ <> 'SHOP',因为NULL <> 'SHOP'

  3. Order by Right(rtrim(tbltransac.No_Faktur),6) Desc删除此内容,因为排序应该在表示层而不是数据层中完成。

  4. 阅读SARG个参数和谓词:

    What makes a SQL statement sargable?

      

    要编写适当的SARG,您必须确保具有的列   它上面的索引仅出现在谓词中,而不是作为一个函数   参数。 SARG必须采用列inclusive_operator的形式    或inclusive_operator列。列名称是唯一的   在表达式的一侧,以及常量或计算值   出现在另一边。包容性运营商包括运营商   =,&gt;,&lt;,=&gt;,&lt; =,BETWEEN和LIKE。但是,仅当您不在开头使用通配符%或_时,LIKE运算符才是包含的   您要将列与

    进行比较的字符串

答案 2 :(得分:1)

如前所述,您的查询中有三个问题。

举个例子,将查询更改为:

SELECT Right(rtrim(tbltransac.No_Faktur),6) as NoUrut,
       tbltransac.No_Faktur,
       tbltransac.No_FakturP,
       tbltransac.Kd_Plg,
       Tblcust.Nm_Plg,
       GRANDTOTAL AS Total_Faktur,
       tbltransac.Nm_Pajak,
       tbltransac.Tgl_Faktur,
       tbltransac.Tgl_FakturP,
       tbltransac.Total_Distribusi 
FROM Tblcust
  INNER JOIN ViewGrandtotal AS tbltransac ON Tblcust.Kd_Plg = tbltransac.Kd_Plg 
WHERE tbltransac.Kd_Trn = 'J'
  and tbltransac.tgl_faktur BETWEEN '20150101' AND '20151231'
  And tbltransac.No_OPJ <> 'SHOP'  
Order by NoUrut Desc --Only if you need a sorted output in the datalayer

另一个想法是,如果你的viewGrandTotal非常大,可以在加入之前对该表进行预过滤。有时SQL Server没有得到一个好的计划,需要一些可爱的触摸才能让他朝着正确的方向前进。

也许这一个:

SELECT Right(rtrim(vgt.No_Faktur),6) as NoUrut,
        vgt.No_Faktur,
        vgt.No_FakturP,
        vgt.Kd_Plg,
        tc.Nm_Plg,
        vgt.Total_Faktur,
        vgt.Nm_Pajak,
        vgt.Tgl_Faktur,
        vgt.Tgl_FakturP,
        vgt.Total_Distribusi 
FROM (SELECT Kd_Plg, Nm_Plg FROM Tblcust GROUP BY Kd_Plg, Nm_Plg) as tc -- Pre-Filter on just the needed columns and distinctive.
INNER JOIN (
        -- Pre filter viewGrandTotal
        SELECT  DISTINCT vgt.No_Faktur, vgt.No_Faktur, vgt.No_FakturP, vgt.Kd_Plg, vgt.GRANDTOTAL AS Total_Faktur, vgt.Nm_Pajak, 
                vgt.Tgl_Faktur, vgt.Tgl_FakturP, vgt.Total_Distribusi 
        FROM ViewGrandtotal AS vgt 
        WHERE tbltransac.Kd_Trn = 'J'
        and tbltransac.tgl_faktur BETWEEN '20150101' AND '20151231'
        And tbltransac.No_OPJ <> 'SHOP'  
    ) as vgt
    ON tc.Kd_Plg = vgt.Kd_Plg 
Order by NoUrut Desc --Only if you need a sorted output in the datalayer

预过滤可以增加更好的计划的生成。

另一个问题可能只是多线程。也许你的查询得到一个并行计划,因为它达到了成本阈值,因为11.000行。由于行数较低,另一个查询只会达到正常计划。您可以通过在SSMS查询中包含实际执行计划来查看生成的计划。

也许你可以比较这些计划以获得线索。如果这没有帮助,您可以在这里发布以获得我的一些反馈。

我希望这会有所帮助。在不知道表格结构,表格大小,性能计数器等的情况下给你提供好的提示并不容易: - )

祝你好运, 离子