【问题标题】:Tuning a SQL query调整 SQL 查询
【发布时间】:2014-01-23 11:25:31
【问题描述】:

我正在尝试调整以下查询,该查询针对 INVENTTABLE 获得了 500k IO,我认为这是一个不错的起点。虽然所有连接的复杂性都让我失望,但我无法总结出一个好的开始?

提前感谢您的任何提示。

SET STATISTICS IO ON

DECLARE
@paramCompany       varchar(3),
@paramCreatedBy     varchar(8000),
@paramCustomer      varchar(100),
@paramBlanketId     varchar(20)

SET @paramCompany = 'adf'
SET @paramCreatedBy = 'All'
SET @paramCustomer = NULL
SET @paramBlanketId = NULL

SELECT
 un.MAINSALESID,
 un.DATAAREAID,
 Sum(un.Quantity) as 'Quantity',
 Sum(un.SalesValue) as 'SalesValue'
INTO #desprel
 FROM
 (SELECT 
  stl.MAINSALESID,
  st.DATAAREAID,
  sl.SALESQTY as 'Quantity',
  sl.SALESQTY * sl.SALESPRICE as 'SalesValue'
 FROM
  DynamicsV5Realtime.dbo.SALESTABLE st
 INNER JOIN
  DynamicsV5Realtime.dbo.SALESLINE sl
 ON
  sl.SALESID = st.SALESID
  and sl.DATAAREAID = st.DATAAREAID
 INNER JOIN
  DynamicsV5Realtime.dbo.INVENTTABLE it
 ON
  it.ITEMID = sl.ITEMID
  and it.DATAAREAID = sl.DATAAREAID
 INNER JOIN
  DynamicsV5Realtime.dbo.SALESTABLELINKS stl
 ON
  stl.SUBSALESID = st.SALESID
  and stl.DATAAREAID = st.DATAAREAID
 INNER JOIN
  DynamicsV5Realtime.dbo.SALESTABLE st1
 ON
  st1.SALESID = stl.MAINSALESID
  and st1.SALESTYPE = 5
 --to get Order created by
 inner JOIN
  --TR  
  vw_R000_EmployeeList pm
 ON 
  --st1.SALESTAKER = pm.emplid
  CASE WHEN st1.SALESTAKER = 'balla' THEN 'gende' ELSE st1.SALESTAKER END = pm.emplid
  and (pm.[NAME] in (SELECT * FROM       udf_MultiValueParameterHandlingString(@paramCreatedBy)) or @paramCreatedBy = 'All')
 WHERE
  st.DATAAREAID = 'adf'
  and st.SALESTYPE = 3 -- Release Order
  and st.SALESSTATUS in (2,3)
  and sl.SALESSTATUS <> 4
  and it.ITEMGROUPID <> 'G0022A'
  and sl.SALESQTY > 0
  and st1.CUSTACCOUNT = IsNull(@paramCustomer,st1.CUSTACCOUNT)
  and st1.SALESID = IsNull(@paramBlanketId,st1.SALESID)
 UNION ALL
 SELECT 
  stl.MAINSALESID,
  st.DATAAREAID,
  sl.SALESQTY as 'Quantity',
  sl.SALESQTY * sl.SALESPRICE as 'SalesValue'
 FROM
  DynamicsV5Realtime.dbo.SALESTABLE st
 INNER JOIN
  DynamicsV5Realtime.dbo.SALESLINE sl
 ON
 sl.SALESID = st.SALESID
 and sl.DATAAREAID = st.DATAAREAID
 INNER JOIN
  DynamicsV5Realtime.dbo.INVENTTABLE it
 ON
  it.ITEMID = sl.ITEMID
  and it.DATAAREAID = sl.DATAAREAID
 INNER JOIN
  DynamicsV5Realtime.dbo.SALESTABLELINKS stl
 ON
  stl.SUBSALESID = st.MARIMSSALESID
  and stl.DATAAREAID = st.DATAAREAID
 INNER JOIN
  DynamicsV5Realtime.dbo.SALESTABLE st1
 ON
  st1.SALESID = stl.MAINSALESID
  and st1.SALESTYPE = 5
 --to get Order created by
 inner JOIN
 --TR  
  vw_R000_EmployeeList pm
 ON 
 --st1.SALESTAKER = pm.emplid
  CASE WHEN st1.SALESTAKER = 'balla' THEN 'gende' ELSE st1.SALESTAKER END = pm.emplid
 and (pm.[NAME] in (SELECT * FROM   udf_MultiValueParameterHandlingString(@paramCreatedBy)) or @paramCreatedBy = 'All')
 WHERE
  st.DATAAREAID = 'adf'
  and st.SALESTYPE = 3 -- Release Order
  and st.SALESSTATUS in (2,3)
  and sl.SALESSTATUS <> 4
  and it.ITEMGROUPID <> 'G0022A'
  and sl.SALESQTY < 0
  and st1.CUSTACCOUNT = IsNull(@paramCustomer,st1.CUSTACCOUNT)
  and st1.SALESID = IsNull(@paramBlanketId,st1.SALESID)     
            ) un
GROUP BY
 un.MAINSALESID,
 un.DATAAREAID

【问题讨论】:

  • 您可能希望标记为 SQL Server,因为调整可能是 RDBMS 特定的。
  • 是的。假设这是 Sql Server,在 SSMS 中运行查询并告诉它生成查询计划。然后我会寻找具有最高百分比的操作并尝试对其进行优化。此外,SSMS 有时会建议新的索引,这会有所帮助:应用它们通常是一件好事!
  • 是的,我正在查看执行计划,最大的索引搜索之一是针对 DIRPARTYCOMMUNICATIONRELA 表 - 它必须是某种内部工作表,因此不确定如何索引它。我希望在如何重写查询以降低总 IO 方面获得一些帮助,这样我就可以在其他地方应用该技术。

标签: sql sql-server performance sql-tuning


【解决方案1】:

只有我一个人还是这个特定的部分有点混乱?我会先解决这个问题。

inner JOIN
  --TR  
  vw_R000_EmployeeList pm
 ON 
  --st1.SALESTAKER = pm.emplid
  CASE WHEN st1.SALESTAKER = 'balla' THEN 'gende' ELSE st1.SALESTAKER END = pm.emplid
  and (pm.[NAME] in (SELECT * FROM udf_MultiValueParameterHandlingString(@paramCreatedBy)) or @paramCreatedBy = 'All')

您能否尝试使用临时表预先找出销售员 ID,然后加入该 ID?在连接条件中使用 udf 和 case 语句可能不是最好的主意。

【讨论】:

  • 是的,我可能应该把它分开
【解决方案2】:

您查看 inventtable 的想法很好。很明显,它的任何字段都没有显示在结果中,也不需要它作为连接其他两个表的链接。因此,它只是为了保证 inventtable 中存在适当的记录。这可以在 EXISTS 子句中完成。

然后检查为什么有两个几乎相似的连接用 UNION ALL 粘合。所有表都被访问两次。这是必要的吗?有一次,您希望所有 sl.salesqty 0 并且你通过 stl.subsalesid = st.salesid 链接。也许您可以执行这一选择语句并且只访问每个表一次。

结果有一个 salestable (st) 字段。这是 st.DATAAREAID。但这实际上是一个搜索和连接条件,因此您可以将其替换为 sl.DATAAREAID 甚至是文字“adf”。所以表 st 中没有字段。也许也只是一个 EXISTS 的东西?

同样,当 salestable 再次被读取为 st1 时。它不是所选列的一部分,因此也许可以将其转换为 EXISTS 子句。

这只是初见,所以我可能会在这里和那里弄错。它只是给你一个开始的东西。

【讨论】:

  • 谢谢。在 EXISTS 点上,我会用 EXISTS 子句替换连接吗?我不知道我还能如何过滤记录。你能提供一个如何做到这一点的例子吗?我保证我会努力理解这一点,而不仅仅是让你为我重写它。
  • 您完全删除连接并将一致的存在子句添加到 where 子句中:...并且存在(从 DynamicsV5Realtime.dbo.INVENTTABLE 中选择 * it.ITEMID = sl.ITEMID 和它.DATAAREAID = sl.DATAAREAID and and it.ITEMGROUPID 'G0022A')
  • 好的我试过了,不幸的是这增加了 IO 的数量和运行时间:(
  • 很抱歉。当结果集包含太多需要查找的行时,就会发生这种情况。我希望情况并非如此。一个 IN 子句可能会有所帮助:...和 ​​sl.ITEMID in(从 DynamicsV5Realtime.dbo.INVENTTABLE 中选择 it.ITEMID it.DATAAREAID = 'adf' and it.ITEMGROUPID 'G0022A')。但是,这可能会导致与原始查询大致相同的执行计划。嗯,你可以试试。
  • 如果幸运的话,您可以反转查询并在 it.DATAAREAID = 'adf' 和 it.ITEMGROUPID = 'G0022A' 的地方询问 NOT In 或 NOT EXISTS。请注意:这绝对是要求不同的东西,但在这种特殊情况下可能是相同的。这取决于表中实际存储的数据。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 2013-02-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多