Sql 如何提高AX查询中左连接的性能

Sql 如何提高AX查询中左连接的性能,sql,sql-server,sql-server-2008,axapta,Sql,Sql Server,Sql Server 2008,Axapta,我正在尝试创建一个查询,以获取dynamics AX salestable记录及其左联接中的历史日志记录。 如果我过滤salesid,我自然会在一瞬间得到结果,但是如果我忽略salesid,它将永远花费时间,即使salesid SN16129492是2017/03/08的唯一“有效”记录: Declare @Bedrijf NVARCHAR(3) = 'dat'; Declare @leverdatum_van DATE = convert(datetime, '2017/03/08'); De

我正在尝试创建一个查询,以获取dynamics AX salestable记录及其左联接中的历史日志记录。 如果我过滤salesid,我自然会在一瞬间得到结果,但是如果我忽略salesid,它将永远花费时间,即使salesid SN16129492是2017/03/08的唯一“有效”记录:

Declare @Bedrijf NVARCHAR(3) = 'dat';
Declare @leverdatum_van DATE = convert(datetime, '2017/03/08');
Declare @leverdatum_tot DATE = convert(datetime, '2017/03/08');
Declare @bedrag decimal = 1;

SELECT     SUM(SALESLINE.LINEAMOUNT) AS waarde, SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID as ordernummer, CUSTTABLE.NAME as klantnaam,
MAX(SalesTable.createdBy) as ingevoerd_door, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus

FROM         SALESLINE INNER JOIN
                      SALESTABLE ON SALESLINE.SALESID = SALESTABLE.SALESID AND SALESLINE.DATAAREAID = SALESTABLE.DATAAREAID 
                      INNER JOIN CUSTTABLE ON
SALESTABLE.DATAAREAID=CUSTTABLE.DATAAREAID AND SALESTABLE.CUSTACCOUNT=CUSTTABLE.ACCOUNTNUM
LEFT JOIN 
(select dbo.CONPEEK(CAST(dbo.CONPEEK(data, 2) AS varbinary(8000)), 2) AS DADER,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 1) AS VELDNUMMER,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 2) AS HUIDIGESTATUS,
dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 3) AS VORIGESTATUS,  LOGRECID 
from SYSDATABASELOG
where TABLE_=366 AND DATAAREAID=@bedrijf 
) log
ON SALESTABLE.DATAAREAID=@bedrijf AND SALESTABLE.RECID=log.LOGRECID
WHERE (SALESLINE.DATAAREAID = @bedrijf) AND SALESTABLE.SALESTYPE=4 --retourorder
AND     (SALESTABLE.SHIPPINGDATEREQUESTED between @leverdatum_van and @leverdatum_tot) 
--AND (Salestable.SALESID = 'SN16129492')
AND (SALESTABLE.SalesOrderStatus in (0,1,2,3,4,5)) 

GROUP BY SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID, CUSTTABLE.NAME, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
HAVING     (SUM(ABS(SALESLINE.LINEAMOUNT))> @bedrag)
是否有办法提高性能/重新设计此查询


这不是答案,但我不能在注释中写这么长的代码。 结果可能不同,但这只是为了帮助我们了解查询的一部分是否会降低性能(分组)。我把一部分组字段移到了外面。 你能试试这个,看看它是否“永远”吗(用你的话)


通过为bot左侧和右侧表添加createddatetime过滤器,我将一个月的处理时间从“永远”减少到<30秒

优化查询:

Declare @Bedrijf NVARCHAR(3) = 'dat';
Declare @leverdatum_van DATETIME = convert(datetime, '2017/03/01');
Declare @leverdatum_tot DATETIME = convert(datetime, '2017/04/01');
Declare @bedrag decimal = 1;

SELECT     SUM(SALESLINE.LINEAMOUNT) AS waarde, SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID as ordernummer, CUSTTABLE.NAME as klantnaam,
MAX(SalesTable.createdBy) as ingevoerd_door, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
FROM     SALESLINE 
INNER JOIN SALESTABLE 
ON SALESLINE.SALESID = SALESTABLE.SALESID AND SALESLINE.DATAAREAID = SALESTABLE.DATAAREAID 
INNER JOIN CUSTTABLE 
ON SALESTABLE.DATAAREAID=CUSTTABLE.DATAAREAID AND SALESTABLE.CUSTACCOUNT=CUSTTABLE.ACCOUNTNUM
LEFT JOIN  (
                           select dbo.CONPEEK(CAST(dbo.CONPEEK(data, 2) AS varbinary(8000)), 2) AS DADER,
                                        dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 1) AS VELDNUMMER,
                                        dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 2) AS HUIDIGESTATUS,
                                        dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 3) AS VORIGESTATUS,  LOGRECID 
                           from SYSDATABASELOG
                           where TABLE_=366 AND DATAAREAID=@bedrijf 
                           and createddatetime between @leverdatum_van and @leverdatum_tot
                    ) log
ON SALESTABLE.DATAAREAID=@bedrijf AND SALESTABLE.RECID=log.LOGRECID
WHERE (SALESLINE.DATAAREAID = @bedrijf) AND SALESTABLE.SALESTYPE=4 --retourorder
AND     (SALESTABLE.createddatetime between @leverdatum_van and @leverdatum_tot) 
--AND (Salestable.SALESID = 'SN16129492')
AND (SALESTABLE.SalesOrderStatus in (0,1,2,3,4,5)) 
GROUP BY SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID, CUSTTABLE.NAME, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
HAVING     (SUM(ABS(SALESLINE.LINEAMOUNT))> @bedrag)
在新的执行计划中寻求更多的聚集索引:


谢谢你帮了我;)

即使只有一个分区,也必须在所有表的条件中显式地包含dataareaid和分区(可以将其添加为筛选器,也可以添加到联接条件中)

默认情况下,AX2012将dataareaid和分区字段作为前两个字段隐式添加到AOT中创建的所有索引中


正如我们所发现的,SQL server在处理这类索引方面是出了名的糟糕,除了如果不显式地提供它(分区),它不能“跳过”第一级之外,它在估计索引统计数据方面也是非常糟糕的(SQL server为索引中的第一个字段绘制直方图,并假设索引中的其余字段具有正态分布)。

与SYSDATABASELOG的左连接是否是性能下降的主要原因?请在SQL server Management Studio上运行此查询,并查看执行计划。瓶颈在哪里(占用时间最多的节点)?。@Etsa当我省略左连接时,需要7秒,而左连接则需要永远。添加了执行计划。42%对于非聚集索引seekOther,然后使用exec计划结果,我将处理函数CONPEEK、CAST(…VARBINARY(8000))的使用以及“数据”Field在15分钟后取消了查询,感谢您的尝试。我认为这可以为您提供一些元素:如果查询的第一部分(与以前一样)足够快,但将联接添加到SYSDATABASELOG执行时间太长,这应该取决于SYSDATABASELOG和/或CONPEEK…如果我保留SYSDATABASELOG的左侧联接,但删除CONPEEK(函数)只需留下:SELECT A.*,log.LOGRECID,它需要6秒钟。如果我过滤sysdatabaselog记录,只选择其中一个日期字段>=SalesTable createddatetime CONVERT(Date,CREATIONDATETIME)>=@leverdatum\u van的记录结果需要30秒……我认为您找到了正确的方法,并且能够一步一步地解决问题。:-)通常使用函数和长文本列会导致性能问题(前一个细化时间,后一个IO页面访问)
Declare @Bedrijf NVARCHAR(3) = 'dat';
Declare @leverdatum_van DATETIME = convert(datetime, '2017/03/01');
Declare @leverdatum_tot DATETIME = convert(datetime, '2017/04/01');
Declare @bedrag decimal = 1;

SELECT     SUM(SALESLINE.LINEAMOUNT) AS waarde, SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID as ordernummer, CUSTTABLE.NAME as klantnaam,
MAX(SalesTable.createdBy) as ingevoerd_door, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
FROM     SALESLINE 
INNER JOIN SALESTABLE 
ON SALESLINE.SALESID = SALESTABLE.SALESID AND SALESLINE.DATAAREAID = SALESTABLE.DATAAREAID 
INNER JOIN CUSTTABLE 
ON SALESTABLE.DATAAREAID=CUSTTABLE.DATAAREAID AND SALESTABLE.CUSTACCOUNT=CUSTTABLE.ACCOUNTNUM
LEFT JOIN  (
                           select dbo.CONPEEK(CAST(dbo.CONPEEK(data, 2) AS varbinary(8000)), 2) AS DADER,
                                        dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 1) AS VELDNUMMER,
                                        dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 2) AS HUIDIGESTATUS,
                                        dbo.CONPEEK(CAST(dbo.CONPEEK(data, 5) AS varbinary(8000)), 3) AS VORIGESTATUS,  LOGRECID 
                           from SYSDATABASELOG
                           where TABLE_=366 AND DATAAREAID=@bedrijf 
                           and createddatetime between @leverdatum_van and @leverdatum_tot
                    ) log
ON SALESTABLE.DATAAREAID=@bedrijf AND SALESTABLE.RECID=log.LOGRECID
WHERE (SALESLINE.DATAAREAID = @bedrijf) AND SALESTABLE.SALESTYPE=4 --retourorder
AND     (SALESTABLE.createddatetime between @leverdatum_van and @leverdatum_tot) 
--AND (Salestable.SALESID = 'SN16129492')
AND (SALESTABLE.SalesOrderStatus in (0,1,2,3,4,5)) 
GROUP BY SALESTABLE.CUSTACCOUNT, SALESTABLE.SALESID, CUSTTABLE.NAME, log.dader, log.veldnummer, log.huidigestatus, log.vorigestatus
HAVING     (SUM(ABS(SALESLINE.LINEAMOUNT))> @bedrag)