Yii2:使用Query vs ActiveRecord构建复杂查询

时间:2015-06-19 17:34:37

标签: php mysql join yii yii2

我有这两个查询,第一个是使用Active Record编写的,第二个是使用yii\db\Query自定义的。在我使用Query编写的localhost查询中,查询速度提高了2-4毫秒,但更难编写。用AR编写的查询也将执行多个数据库查询以及SHOW CREATE TABLE,总共就像执行AR时执行的更多或10个查询。 Plus AR要求您为关系网络中的每个表定义AR模型,而如果您避免AR,则最终会在您的应用中使用较少的类/文件。

我的问题是,您会使用AR还是会使用yii\db\Query撰写查询? AR更漂亮,更容易编写,但它产生了很多查询,这是一个问题吗?我正在一个桌子上有几百万行的网站上工作,每天大约有10万次网站访问。

AR查询:

return self::find()->select('id, news_users_id')
                   ->with([
                        'newsUsers' => function ($query) {
                            $query->select(['ID', 'cmpid']);
                        },
                    ])
                   ->with([
                        'newsUsers.firme' => function ($query) {
                            $query->select(['id', 'skraceni_naziv']);
                        },
                    ])
                   ->with([
                        'newsUsers.firmeBh' => function ($query) {
                            $query->select(['id', 'skraceni_naziv']);
                        },
                    ])
                   ->with([
                        'newsUsers.firmeOstalo' => function ($query) {
                            $query->select(['id', 'skraceni_naziv']);
                        },
                    ])
                   ->orderBy(['id' => SORT_DESC])
                   ->limit(6)
                   ->all();

查询:

$query = new Query;

$query->select(['club.id',
                'firme.id', 'firme.skraceni_naziv',
                'firme_bh.id', 'firme_bh.skraceni_naziv',
                'firme_ostalo.id', 'firme_ostalo.skraceni_naziv']) 

      ->from('club')
      ->innerJoin('news_users', 'club.news_users_id = news_users.ID')
      ->leftJoin('firme', 'news_users.cmpid = firme.id')
      ->leftJoin('firme_bh', 'news_users.cmpid = firme_bh.id')
      ->leftJoin('firme_ostalo', 'news_users.cmpid = firme_ostalo.id')
      ->orderBy(['club.id' => SORT_DESC])
      ->limit(6);

$command = $query->createCommand();

return $command->queryAll();

2 个答案:

答案 0 :(得分:4)

首先,可以缓存您的架构并避免那些“SHOW CREATE TABLE”查询。使用enableSchemaCache对象的db属性进行设置。

其次,连接并不总是填充相关记录的最佳方式。例如,如果表A中的每个条目在表B中具有许多相关条目,则将B加入A将导致来自表A的条目被重复。这可能是性能问题。

因此yii2有with()joinWith()。使用with()获取相关表将进行2次查询,但更多时候这样做会更有效。

最后,一旦掌握了AR,AR就是一个非常方便的工具。对我来说,它的好处超过了开销。

答案 1 :(得分:3)

首先:ActiveRecord :: find()方法返回扩展Query类的ActiveQuery实例。因此,您可以使用ActiveRecord :: find()使用Query对象执行的所有操作。

不同之处在于:ActiveQuery有一些额外的方法,包括'with'方法,它与'join'方法不同,因为它运行了你已经知道的额外数据库请求。使用ActiveQuery和'with'方法的结果是ActiveRecord对象作为主要结果及其关系。在另一方面,Query将仅返回数据库数据作为数组,因此您将错过ActiveRecord方法。

如果性能很重要,最好通常使用连接,因为它只需要一个db请求。但是很多联合数据对性能也很重要。因此,如果您遇到性能问题,我相信您需要做出一些特别的决定。