laszlovl / yii2-staticactiverecord
一个对 Yii2 的 ActiveRecord 进行了多种性能优化,但牺牲了少许灵活性的版本
Requires
- yiisoft/yii2: ~2.0
Requires (Dev)
- yiisoft/yii2-dev: ~2.0
This package is not auto-updated.
Last update: 2024-09-28 16:41:33 UTC
README
一个更快但略少灵活的 Yii2 ActiveRecord 版本。
描述
Yii2 是一个优秀的框架,其灵活性是其优点之一。然而,灵活性往往是以性能为代价的,有时性能的损失可能不值得。
此代码专门针对 Yii2 的 ActiveRecord。由于 ActiveRecord 的灵活性,许多计算必须在运行时完成:查找相应的数据库模式、从该模式中推导出属性列表、根据模型的 rules()
确定每个场景的安全属性等。
在 Yii2 的架构中,这些计算不仅针对你的每个 ActiveRecord 类 进行一次(每个请求),而且针对每个 ActiveRecord 实例 进行。
以下是一个示例代码
foreach (Cat::find()->limit(100)->all() as $cat) { echo $cat->owner; }
对 ->owner
的调用将被转发到 __get()
,然后调用 hasAttribute()
,再调用 attributes()
,然后调用 getTableSchema()
,这将使用 DI 容器检索对 db
组件的引用,等等。所有这些只是为了确定你的 Cat 类是否有一个本地属性 $owner
,或者应该将其解析为 ActiveRecord 属性,或者可能是关系。这不是只进行一次,而是 100 次:为你的每个 Cat 实例再次进行。
这些都是必要的吗?这当然取决于你的应用程序的设计方式。例如,在运行时向对象附加行为是完全可能的,这可能导致你的猫中有一个 owner
关系,而另一个没有。或者,可以覆盖 attributes()
来根据实例的其他属性值完全隐藏 owner
属性。
但在许多应用程序中并非如此:虽然类不同的实例当然会有不同的 值,但它们的 元数据 将是 静态的:要么你的所有 Cats 都有一个属性 owner
,要么一个也没有。如果你的某个猫实例被发现在具有 MiowBehavior
,则所有其他猫也会具有它。
如果你的应用程序确实如此,我们可以在类级别缓存此元数据:一旦为类的某个实例计算过,其他实例就可以立即查找。此扩展的 ActiveRecord
就是这样做的,通过使用静态类变量在包含类的所有实例之间缓存函数的结果。
这可以极大地提高你应用程序的性能,尤其是在处理大量相同类实例的请求中,如具有大分页大小的 GridView 或 ListView,或在资源集合上的 API 调用。
基准测试
此扩展包含一个基准测试工具,用于测量几个非常简单场景的性能改进。在所有情况下,都创建了 1000 个同一类的实例。
~/yii2-staticactiverecord/benchmark$ ./yii benchmark
Benchmarking benchmarkGetProperty...
Regular ActiveRecord: 0.0089842319488525
Static ActiveRecord: 0.0069756507873535
Improvement: 23%
Benchmarking benchmarkSetProperty...
Regular ActiveRecord: 0.009577751159668
Static ActiveRecord: 0.0076509952545166
Improvement: 21%
Benchmarking benchmarkValidate...
Regular ActiveRecord: 0.046598815917969
Static ActiveRecord: 0.03521466255188
Improvement: 25%
单个请求中性能改进的总和当然取决于你的具体应用程序,但我已经能够将应用程序的一个重请求的响应时间降低超过 50%。
测试
此扩展重用了 Yii 的现有 ActiveRecordTest 套件,用此扩展中的实现覆盖了默认的 ActiveRecord 实现。这表明 Yii 中包含的任何测试用例都没有因此扩展的行为而损坏。
注意事项
正如所说,这个扩展并不适用于所有人。以下是一些可能不适合特定类的迹象:
- 该类覆盖了以下任何函数:
getTableSchema()
、primaryKey()
、attributes()
、hasAttribute()
、scenarios()
- 在类的这些函数中有一个对
$this
的引用:rules()
、behaviors()
、tableName()
- 您的应用程序在运行时将行为附加到该类
- 您的应用程序在类的表上调用
getTableSchema($refresh=true)
安装
通过composer:composer require laszlovl/yii2-staticactiverecord
之后,只需从lvl\staticactiverecord\db\ActiveRecord
扩展您的ActiveRecord类,而不是yii\db\ActiveRecord
。