tsql 查询分析器:如何降低“成本”?

Posted

技术标签:

【中文标题】tsql 查询分析器:如何降低“成本”?【英文标题】:tsql query analyzer : how do you reduce "cost"? 【发布时间】:2009-05-07 19:23:09 【问题描述】:

我正在对以下查询运行 sql 分析器

SELECT bl.Invoice_Number, bl.Date_Invoice, ti.TranNo, bt.Description,
    CONVERT(decimal(15,2), bl.Invoice_Amount) AS Invoice_Amount, co.Company_ID, co.Account_Nbr,
    isnull(bl.Reference,' ') as Reference, bl.Billing_Log_RecID AS BillingKey
    FROM [CONN.domain.NET].cwwebapp.dbo.Billing_Log bl
    LEFT JOIN [App].dob.tarInvoice ti
        ON bl.Invoice_Number = dbo._fnStripLeadZeros(ti.TranNo)
    INNER JOIN [CONN.domain.NET].cwwebapp.dbo.Billing_Type bt
        ON bl.Billing_Type_ID = bt.Billing_Type_ID
    LEFT JOIN [CONN.domain.NET].cwwebapp.dbo.Company co
        ON  bl.Company_RecID = co.Company_RecID
    WHERE bl.Date_Invoice >= '2009-05-05'
        AND ti.TranNo IS NULL
        AND bl.Invoice_Amount <> 0
        AND bl.Billing_Type_ID <> 'D'
        AND bl.Billing_Type_ID <> 'P'
--      AND bl.Billing_Type_ID <> 'M'
Order By bl.Invoice_Number

查询在 [App] 服务器上运行并连接到 [Conn] sql server 进行连接 图表告诉我

remote query cost : 62%
customered index scan [App].[dbo].tarInvoice.[PK__...  Cost : 34% 

此查询需要 2 分钟才能运行。关于如何弄清楚如何更有效地运行的任何想法?我猜这与连接到同一网络上的另一个 sql 服务器有关。

提前致谢。

【问题讨论】:

@phill 说“你怎么知道怎么做?”,经验,经验,经验,还有这个提示:当查询运行缓慢时,请执行以下操作:运行 SET ShowPlan_All ON,然后运行您的查询,查看单词“scan”的输出。你的问题就在那里。 “扫描” = 触摸每一行(表格或索引)。您想“扫描”电话簿还是使用索引?修改时不能使用索引,所以我建议你不要修改它。您可以修改与索引进行比较的搜索字符串(bl.Invoice_Number)并仍然使用索引 【参考方案1】:

您正在对 tarInvoice 聚集索引进行完整扫描(触摸每个索引条目),看看您是否可以删除函数调用 dbo._fnStripLeadZeros(ti.TranNo) 以便它使用索引。

可能在 bl.Invoice_Number 上添加前导零并加入未更改的 ti.TranNo

编辑

添加不带前导零的计算列并添加索引:

ALTER TABLE dbo.tarInvoice ADD TranNoZeroFree AS Convert(int,TranNo) PERSISTED 
GO
CREATE NONCLUSTERED INDEX IX_tarInvoice_TranNoZeroFree ON dbo.tarInvoice (TranNoZeroFree) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

【讨论】:

成功了..你怎么知道怎么做?你能推荐任何文章来阅读这个吗? @phill 说“你怎么知道怎么做?”,经验,经验,经验,还有这个提示:当查询运行缓慢时,请执行以下操作:运行 SET ShowPlan_All ON,然后运行您的查询,查看单词“scan”的输出。你的问题就在那里。 “扫描” = 触摸每一行(表格或索引)。您想“扫描”电话簿还是使用索引?修改时不能使用索引,所以我建议你不要修改它。您可以修改与索引进行比较的搜索字符串 (bl.Invoice_Number) 并仍然使用该索引。 @phil,只要你有一个处于连接条件的函数,这都是一件坏事。函数对于性能的影响可能与游标一样糟糕,应尽可能避免使用。 我回去检查了输出,结果不正确,我需要匹配前导零。 @Phil,bl.Invoice_Number 和 ti.TranNo 的数据类型是什么,格式如何?【参考方案2】:

尝试将远程服务器添加为linked server。

【讨论】:

查询似乎表明他已经在使用链接服务器?名称为 [CONN.domain.NET] 他使用 4 部分命名,除非可以命名链接服务器 [CONN.domain.NET]。 四部分表名的第一部分是远程服务器,对吧?第二部分是在本地服务器上切换数据库。像 server.database.schema.table。 我不认为数据库是链接的..我该如何检查?【参考方案3】:

只使用了一个本地表,因此您可以将更多查询转移到另一台服务器:

select *
from openquery([CONN.domain.NET],'
SELECT bl.Invoice_Number, bl.Date_Invoice, ti.TranNo, bt.Description,
    CONVERT(decimal(15,2), bl.Invoice_Amount) AS Invoice_Amount,
    co.Company_ID, co.Account_Nbr, isnull(bl.Reference,'' '') as Reference,
    bl.Billing_Log_RecID AS BillingKey
    FROM cwwebapp.dbo.Billing_Log bl
    INNER JOIN cwwebapp.dbo.Billing_Type bt
        ON bl.Billing_Type_ID = bt.Billing_Type_ID
    LEFT JOIN cwwebapp.dbo.Company co
        ON      bl.Company_RecID = co.Company_RecID
    WHERE bl.Date_Invoice >= ''2009-05-05''
        AND bl.Invoice_Amount <> 0
        AND bl.Billing_Type_ID <> ''D''
        AND bl.Billing_Type_ID <> ''P''
') remote
LEFT JOIN tarInvoice ti
    ON remote.Invoice_Number = dbo._fnStripLeadZeros(ti.TranNo)
WHERE ti.TranNo IS NULL
Order By remote.Invoice_Number

不确定确切的语法,只是试图指出可能的改进方向。

【讨论】:

我尝试执行上述操作并收到返回的消息“无法完成延迟准备”不知道这是什么意思.. 对不起,我是这个的新手 表示openquery() 的查询参数不是正确的sql。您可以在另一台服务器上尝试以获取更详细的消息,但由于 KM 已经解决了问题,这有点没有实际意义 :) 是的,但我仍然想学习不同的方法来做同样的事情。这仍然是一个非常有趣的方法【参考方案4】:

我还建议,如果您必须在查询中转换数据,例如: 转换(十进制(15,2),bl.Invoice_Amount) 那么您需要考虑重构您的数据库以使用正确的数据类型。

【讨论】:

以上是关于tsql 查询分析器:如何降低“成本”?的主要内容,如果未能解决你的问题,请参考以下文章

如何从列数未知的存储过程中查看 Toad 中结果集的内容?

如何降低通过链接服务器执行的查询的成本

降低表值函数的成本 - 查询计划中的 XML 阅读器 - 如何?

Bigquery 集群不会降低查询成本

鸿蒙内核源码分析(管道文件篇) | 如何降低数据流动成本 | 百篇博客分析OpenHarmony源码 | v70.01

如何根据另一列的条件查询同一列两次?