简介

本文档由 Mendix 社区创建并为Mendix社区创建。它以“注意事项”和“注意事项”的形式收集性能最佳实践。

应用程序必须具备的条件是性能良好。如果性能不好,用户将不会接受任何东西,而会选择替代品。本文描述了在开发过程中应用的一些最佳实践,以便获得性能更好的应用程序。

一切都应该尽可能简单,但不能简单。——爱因斯坦

过早优化是万恶之源。—— Donald Knuth

这两个名言都建议不要为了性能而使用困难的构造,除非真的需要它们并且已经研究过更简单的替代方案。可能需要进行负载测试和并有良好的测量工具,但这超出了本文档的范围。

其他最佳实践可能与性能最佳实践相冲突。例如,安全性可能需要事件处理程序,而性能需要最小化它们。良好的架构通常是不同质量方面之间的权衡。所以,做出积极的选择。

本文档包含涵盖Mendix Studio Pro,可以在其中考虑域模型(有一个关于索引的特殊部分)、微流和页面的性能。其他部分涵盖了Mendix领域特定语言(例如 XPath、expressions和 OQL)中特殊性能注意事项的部分基础设施。

领域模型的最佳实践

如果要对应用程序的领域模型进行简单合理的设计,应考虑以下几点:

  • 为实体创建索引,可获得100以上的记录,并且可查询除Mendix引用/ID之外所有的。
  • 尽量不使用计算属性,因为它们会在每次检索和列表的每行检索时触发。很少需要这种条件可见性。
  • 尽量不使用事件句柄(event handler),因为它们会在每个事件(例如commit)触发。
  • 尽量不使用引用集合关联。Mendix在每次查询时返回ID(列表查询的每行),因此,大量的引用,并且特别是引用集合将导致额外的查询,将导致额外的数据库负载。
  • 如果数据卷变得太大,且并不总是需要时刻保留所有的数据,请考虑将数据归档。甚至可以创建两个相似的实体,一个包含当前使用的数据,另一个仅包含用作报表或其他历史原因的数据。
  • 考虑使用反规范化的数据,这意味着将属性复制到其他的实体中。这样,数据每次不再从源实体中获取。如果数据改变不多,这样将节省大量的查询。但是,需要构建保持复制的属性同步的逻辑。
  • 请勿对实体使用多层继承和太多的泛化,那将包含大量的数据,特别是使用XPath访问实体时,对大数据集会将泛化的安全规则添加给XPath而将产生复杂的查询,导致慢查询。请考虑以下替代方案:
    • 在一个实体中组合属性,并添加枚举来决定它的泛化。
    • 对于单个实体添加一对一关系的范型。根据UI需要,这些一对一关系可能是从专业化到泛化的正常引用,以节省预取时间。
    • 通过业务逻辑,添加继承中的非持久化层来处理。
  • 请勿对持久化实体使用临时关联。在屏幕/UI逻辑中使用非持久化实体。
  • 在实体间避免使用多于一个的关系,特别是如果这类关系有不同的访问级别。相反,应该在其中某个实体中使用枚举,或者在实体间添加一个中介实体包含关联类型的枚举。例如,如果不同类型的用户访问一个文档,请勿创建Document_OwnerDocument_EditorDocument_Viewer等,相反,请在实体间添加一个名为DocumentAccess的中介实体,该中介实体包含名为AccessType的枚举,其可能的值为OwnerEditor或者Viewer

索引的最佳实践

在数据库界,索引是最佳实践长久的主题。对于Mendix应用,应采用以下最佳实践:

  • 根据需要尽可能多创建索引。虽然每个索引都占用空间,而且insertupdatedelete语句将变慢,但查询将受益匪浅。
  • 由于Mendix取回对象的所有列,需要索引有两方面的原因。第一个原因是为了快速地获取唯一的Mendix内部的ID,第二个原因是为了排序。
  • 在一个索引中,仅需要覆盖搜索语句和排序语句。
  • 对于同一个属性开头的不必创建不同的索引。
  • 根据经验,尽量减少索引列的数量。请保持在三个以下,最多使用五个。
  • 请以最具选择性的属性开头,虽然需要考虑对单个属性的查询仅使用以该属性开头的索引。
  • 索引只被用来匹配相等、一定范围的日期、数值查询,以及前导/startsWith的字符串查询。
  • 索引扫描可发生在更复杂的语句如contains或者endsWith中。这些仍比全表扫描快。

微流(Microflow)的最佳实践

  • 最小化循环中的工作
    • 如果提交列表,应在循环之后提交
    • 如果需要,在循环之前创建名为_CommitList的列表,用来存放要提交的数据项。
    • 对于循环中的查询,考虑在循环之前获取所有的数据,在循环内部再对该列表进行查找。
    • 如果循环包含条件选择,请考虑决策逻辑是否可以是循环之前的最小化遍历的查询。
  • 如果对象或列表可作为参数传递,请避免不必要的查询。
  • 懂得并使用检索+聚合的优化。如果取回一个列表并对列表进行计数,Mendix将此优化为一个查询。如果在微流中在某些决策之后需要这个列表,明智的做法是再次检索数据,以便只获取所需的数据。这也适用于批处理,那样可以在单独的查询中对检索的总数进行优化,并取回检索块。
  • 尽可能使用关联进行检索。这会使用缓存,更高的可读性,并使用索引。如果业务逻辑需要数据库值(因为通过关联的值可能会改变),那么数据库检索当然是必需的。
  • 尽可能晚地提交。提交会对记录(或者记录列表)加锁。这意味着其他用户/逻辑需要对同一个对象进行提交的,必须等待前面的事务执行完成。
  • 为了防止锁定,请执行小块提交数据的计划事件。这样数据就不会在更长的时间内被锁定。

页面的最佳实践

  • 保持简洁。如果可能,分成多个页面。考虑移动App的逻辑,而不是一屏大而全的逻辑。
  • 尽量减少发送的数据,例如使用分块或安全性来防止数据传输给客户端。
  • 尽量避免多个相同的数据源,因为它们将多次加载对象。
  • 最小化条件可见性。
  • 给用户以反馈。如果这需要几秒以上的时间,请提供进度提示。
  • 如果用户不必等待结果,请使用异步的方式。例如,通过界面发送邮件或者更新其他应用永远不应该是用户在UI中要等待的东西。对于异步执行,可选Mendix应用市场中的社区公共功能库(Community Commons Function Library )来在后台运行微流,或者使用任务队列来控制负载并防止后台工作高峰。
  • 在表格组件(data grid)中使用某个属性过滤相关联的实体时,建议在下拉搜索字段中限制可能的选项,以便仅获取与表格中实体有关联的对象。例如,有一个Order实体的表格,添加下拉搜索框以按Order_Customer/Customer/Name进行过滤。将以下XPath约束添加到下拉搜索字段中将是有益的: [Order_Customer/Order]。这样,只有带有Order的Customer将在下拉搜索中可用。这是必要的,因为在某些数据库中,即使所有的索引都到位,过滤不存在的条件也很慢。

基础设施的最佳实践

  • 获得更好的基础设施(例如,Mendix Cloud上更多的应用引擎)。
  • 如果私有化部署,确保在Mendix之前配置web代理服务器来处理静态页面和压缩数据。

XPath的最佳实践

  • 在XPath语句中,避免使用"不等于"和"not"语句。通常可以重写为肯定语句,比如:
    <boolean>=false(), <enumeration> = valueA, <enumeration> = valueB, integer>valueA, 或者integer<valueB
  • 如果查询逻辑允许,对同一个关联实体使用组合路径进行查询。
  • 在老版本的PostgreSQL数据库中,使用属性开头的XPath是明智之举,因为数据库查询优化器按顺序处理语句。如今,据称查询优化器有所改善,这一规则不再需要。
  • 确保所用的属性已建索引。
  • 如果一个角色对于同一个实体有两个访问规则,一个提供只读访问权限,另一个提供读写访问权限,请勿让这些访问规则独占。请将只读规则包含读写规则。例如,如果访问级别基于布尔属性Editable,创建两个访问规则如下:第一保证对所有对象(无约束)的只读访问,第二保证对一些对象的读写访问(约束:[Editable = true()])。请勿对第一个访问规则添加约束[Editable = false()],因为这样会在生成SQL时产生不必要的复杂性。

OQL的最佳实践

对于OQL,许多与XPath相同的最佳实践都适用。

注意:OQL查询不会安全地获取领域模型,因此可能需要在合适的时候添加额外的语句(例如,多租户应用程序中)

安全的最佳实践

  • 尽量减少每个用户的角色数量
  • 尽量减少每个实体的规则数量

Web服务和XML的最佳实践

  • 使用SSHA256而不是BCrypt
  • 对于schema的校验将减慢处理速度
  • 对于微流使用子事务将减慢处理速度

MxAssist性能的最佳实践

MxAssist Performance Bot 有助于发现潜在的性能问题以进行改进。可以通过"View">"MxAssist Performance Bot"进行访问。

更详细的性能最佳实践,请参考Mendix最佳性能实践

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐