第十七章 性能(二)
由于原著作版权问题,看到本文的哥们请勿转载,本文仅供与各位AX从业者和爱好者学习讨论之用,期待您的赐教.
事务性能
(译注:正如前面提到的,Transaction Performance在这里翻译成事务性能并不能很好地表达这一节所记述的内容,不过我没想到更好的翻译方式)
前一节我们把注意力放在了限制客户端和服务器之间的通讯量上,但是这两层只涉及到了DyanmicsAX应用运行三层中的两层。最后一层是数据库层,优化服务器层和数据库层的数据包交换也很重要.本节将注意力放在优化应用逻辑执行的事务部分(译注:原文是"transactional part",意思应该是与数据库打交道的部分,翻译成事务和交易都蛮别扭).DynamicAX应用运行时通过批操作(译注:原文"Set-based operators"翻译成批操作应该没什么问题)和数据缓存来减少服务器层对数据库层的调用.当然,也应该注意从数据库层发送到服务器层的数据.不仅数据会更快地从数据库中获取,而且需要返回的数据包和消耗的内存也会减少。所有的这些将会使应用逻辑更快地执行,更小的事务范围(译注:原文 transaction scopes这里的事务是通常意义上的数据库事务),更少的锁定和堵塞,改进的并发和吞吐量控制.
批量数据操作
正如在第12章,"数据库层"(译注:第12章也是写得非常精彩的一章!),在讨论数据库触发方法时简略提到的那样,X++语言包含一些操作和类支持数据库的批量操作。批操作语句比记录操作语句(译注:原文"record-set",就是逐条操作数据库中的记录)---减少了与数据库的交互(译注:原文用的是"round trips",字面理解应该是往返,就是服务器层与数据库层之间的你来无往,翻译成往返总感觉别扭).下面的X++代码示例显示了选取多条custTable记录,然后用新的值逐条更新creditMax字段,说明了select语句的执行需要与数据库需要一次交互并且每次执行update方法也要发生一次交互.
(译注:我跟踪了一下举例中所执行的SQL语句,select这个语句没有疑义,不过 update是否执行了100次值得探究,我测试的结果是如果creditMax这个字段值原来就是1000的话,并不会执行update语句,也就是说如果反复运行上面的语句,则只会执行select语句,update语句并不会执行,AX运行时应该有个在服务器端比较的过程,如果更新值跟原来的值相等并不会提交给数据库服务器引擎.可能这个地方作者是为了说明批量做了简化,或者我的理解有问题,这个还需要进一步讨论)
理论上,前面介绍的场景通过改写成下面的X++代码可以与数据库只发生一次交互。下面的代码展示了如何利用update_recordset操作符转化为传递给数据库服务器的一个SQL Update语句.
重要 对临时表使用批操作并不会提升效率.DynamicsAX应用运行时总会把批处理降级成记录操作(译注:即一条条地执行)。不管表是如何变成临时表(在表属性的里数据里或者显式通过X++代码)(译注:上面括号部分的原文如下"whether specified in metadata in the table properties,disabled because of the configuration of the DynamicsAX application,or explicitly stated in the X++ code using he table",其中中间的一句不知道原作者的意思是什么,是说在表属性里设置表为临时表这种做法会通过配置禁用掉?我在配置里没找到这样的选项,一时理解不了,把原文贴出来,知道的哥们指点一下)都会做降级处理.同时,被应用运行时降级后总会调用表的doInsert,doUpdate和doDelete方法,所以在重载的方法中所添加的应用逻辑将不会被执行(译注:意思就是如果重载了insert,update,delete等方法,并且添加了自己的逻辑处理,由于被降级的批处理语句会直接执行do*方法将会绕过这些方法的执行,自己添加的逻辑也就不会被执行了).
insert_recordset操作
insert_recordset操作可以只通过一次与数据库的交互插入多条记录.下面的X++代码展示了如何用这个操作把一个产品的尺寸拷贝到另一个产品中.上面提到的另一个产品(译注:原文是The item to which the sizes are copied,小学语文没学好,还真不知道怎么表述,还是用另一个产品来表述明确些,知道是什么意思就可以了,呵呵)从inventTable表中选取.
1.上面insert_recordset语句中的select 部分执行的时候会把选取的行插入临时创建的表(译注:这里的临时表是数据库中的临时表,跟X++中的临时表不是一回事)中,在SQL Server2000中执行上述select时类似于 SELECT <field list>INTO <temporay table> FROM<source tables>WHERE<predicates>.
2.临时表中的数据通过类似于INSERT INTO<target table>(<field list>)SELECT <field list>FROM<temporary table>.的语句插入目的表.
3.通过执行DROP TABLE<temporary table>删除临时表
事务性能
(译注:正如前面提到的,Transaction Performance在这里翻译成事务性能并不能很好地表达这一节所记述的内容,不过我没想到更好的翻译方式)
前一节我们把注意力放在了限制客户端和服务器之间的通讯量上,但是这两层只涉及到了DyanmicsAX应用运行三层中的两层。最后一层是数据库层,优化服务器层和数据库层的数据包交换也很重要.本节将注意力放在优化应用逻辑执行的事务部分(译注:原文是"transactional part",意思应该是与数据库打交道的部分,翻译成事务和交易都蛮别扭).DynamicAX应用运行时通过批操作(译注:原文"Set-based operators"翻译成批操作应该没什么问题)和数据缓存来减少服务器层对数据库层的调用.当然,也应该注意从数据库层发送到服务器层的数据.不仅数据会更快地从数据库中获取,而且需要返回的数据包和消耗的内存也会减少。所有的这些将会使应用逻辑更快地执行,更小的事务范围(译注:原文 transaction scopes这里的事务是通常意义上的数据库事务),更少的锁定和堵塞,改进的并发和吞吐量控制.
批量数据操作
正如在第12章,"数据库层"(译注:第12章也是写得非常精彩的一章!),在讨论数据库触发方法时简略提到的那样,X++语言包含一些操作和类支持数据库的批量操作。批操作语句比记录操作语句(译注:原文"record-set",就是逐条操作数据库中的记录)---减少了与数据库的交互(译注:原文用的是"round trips",字面理解应该是往返,就是服务器层与数据库层之间的你来无往,翻译成往返总感觉别扭).下面的X++代码示例显示了选取多条custTable记录,然后用新的值逐条更新creditMax字段,说明了select语句的执行需要与数据库需要一次交互并且每次执行update方法也要发生一次交互.
static void UpdateCustomers(Args _args)
{
CustTable custTable;
;
ttsbegin;
while select forupdate custTable
where custTable.CustGroup == '40' //Round trip to database
{
custTable.CreditMax = 1000;
custTable.update(); //Round trip to database
}
ttscommit;
}
如果custGroup这个字段等于'40'的custTable记录有100条,那么与数据库发生交互的次数会是1select+100updates=101次.select语句发生交互的次数可能会稍微多一些,这取决于一次可以从数据库获取并发送到AOS的custTable纪录的条数.{
CustTable custTable;
;
ttsbegin;
while select forupdate custTable
where custTable.CustGroup == '40' //Round trip to database
{
custTable.CreditMax = 1000;
custTable.update(); //Round trip to database
}
ttscommit;
}
(译注:我跟踪了一下举例中所执行的SQL语句,select这个语句没有疑义,不过 update是否执行了100次值得探究,我测试的结果是如果creditMax这个字段值原来就是1000的话,并不会执行update语句,也就是说如果反复运行上面的语句,则只会执行select语句,update语句并不会执行,AX运行时应该有个在服务器端比较的过程,如果更新值跟原来的值相等并不会提交给数据库服务器引擎.可能这个地方作者是为了说明批量做了简化,或者我的理解有问题,这个还需要进一步讨论)
理论上,前面介绍的场景通过改写成下面的X++代码可以与数据库只发生一次交互。下面的代码展示了如何利用update_recordset操作符转化为传递给数据库服务器的一个SQL Update语句.
static void UpdateCustomers(Args _args)
{
CustTable custTable;
;
ttsbegin;
update_recordset custTable setting creditmax = 1000
where custTable.CustGroup == '40'; //Single round trip to database
ttscommit;
}
由于几个原因,使用custTable并不会产生只交互一次的结果。这个将在后面介绍DynamicsAX应用运行时支持的每一个批处理语句的时候说明,这些部分也会介绍如何更改上面的语句以确保只与数据库发生一次交互,即使使用custTable.{
CustTable custTable;
;
ttsbegin;
update_recordset custTable setting creditmax = 1000
where custTable.CustGroup == '40'; //Single round trip to database
ttscommit;
}
重要 对临时表使用批操作并不会提升效率.DynamicsAX应用运行时总会把批处理降级成记录操作(译注:即一条条地执行)。不管表是如何变成临时表(在表属性的里数据里或者显式通过X++代码)(译注:上面括号部分的原文如下"whether specified in metadata in the table properties,disabled because of the configuration of the DynamicsAX application,or explicitly stated in the X++ code using he table",其中中间的一句不知道原作者的意思是什么,是说在表属性里设置表为临时表这种做法会通过配置禁用掉?我在配置里没找到这样的选项,一时理解不了,把原文贴出来,知道的哥们指点一下)都会做降级处理.同时,被应用运行时降级后总会调用表的doInsert,doUpdate和doDelete方法,所以在重载的方法中所添加的应用逻辑将不会被执行(译注:意思就是如果重载了insert,update,delete等方法,并且添加了自己的逻辑处理,由于被降级的批处理语句会直接执行do*方法将会绕过这些方法的执行,自己添加的逻辑也就不会被执行了).
insert_recordset操作
insert_recordset操作可以只通过一次与数据库的交互插入多条记录.下面的X++代码展示了如何用这个操作把一个产品的尺寸拷贝到另一个产品中.上面提到的另一个产品(译注:原文是The item to which the sizes are copied,小学语文没学好,还真不知道怎么表述,还是用另一个产品来表述明确些,知道是什么意思就可以了,呵呵)从inventTable表中选取.
static void CopySizes(Args _args)
{
InventSize inventSizeTo;
InventSize inventSizeFrom;
InventTable inventTable;
;
ttsbegin;
insert_recordset inventSizeTo(ItemId,InventSizeId,Description,Name)
select itemId from inventTable
where inventTable.ItemId == 'PB-Metal Shade'
join inventSizeId,description,name from inventSizeFrom
where inventSizeFrom.ItemId == 'PB-Plastic Shade';
ttscommit;
}
与数据库的交互将会在数据库中执行三条语句(译注:由于后文要介绍的几个原因,上面的这个例子并是按照下面的介绍的方式执行的,姑且看之,后面会介绍如何保证批操作不被降级):{
InventSize inventSizeTo;
InventSize inventSizeFrom;
InventTable inventTable;
;
ttsbegin;
insert_recordset inventSizeTo(ItemId,InventSizeId,Description,Name)
select itemId from inventTable
where inventTable.ItemId == 'PB-Metal Shade'
join inventSizeId,description,name from inventSizeFrom
where inventSizeFrom.ItemId == 'PB-Plastic Shade';
ttscommit;
}
1.上面insert_recordset语句中的select 部分执行的时候会把选取的行插入临时创建的表(译注:这里的临时表是数据库中的临时表,跟X++中的临时表不是一回事)中,在SQL Server2000中执行上述select时类似于 SELECT <field list>INTO <temporay table> FROM<source tables>WHERE<predicates>.
2.临时表中的数据通过类似于INSERT INTO<target table>(<field list>)SELECT <field list>FROM<temporary table>.的语句插入目的表.
3.通过执行DROP TABLE<temporary table>删除临时表