我使用的是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管理日志,我找不到任何错误或阻止连接。也没有错误的路由..
请帮助......它发生在一周前,在此之前很好,而且我已经超过一个月没有触摸服务器......
答案 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)
以下是一些建议:
year(tbltransac.tgl_faktur)=2015
将此替换为tbltransac.tgl_faktur >= '20150101' and tbltransac.tgl_faktur < '20160101'
ISNULL(tbltransac.No_OPJ,'') <> 'SHOP'
将其替换为tbltransac.No_OPJ <> 'SHOP'
,因为NULL <> 'SHOP'
。
Order by Right(rtrim(tbltransac.No_Faktur),6) Desc
删除此内容,因为排序应该在表示层而不是数据层中完成。
阅读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查询中包含实际执行计划来查看生成的计划。
也许你可以比较这些计划以获得线索。如果这没有帮助,您可以在这里发布以获得我的一些反馈。
我希望这会有所帮助。在不知道表格结构,表格大小,性能计数器等的情况下给你提供好的提示并不容易: - )
祝你好运, 离子