使用 Doctrine 2 DQL 查询包含大量数据的 LEFT JOIN 的最有效方法是什么



我有一个实体"硬币"与价格上的oneToMany相关联。价格每分钟更新一次,有数百万个条目。

我试图实现的是一个 DQL 查询,它将获取迄今为止的最后价格。

现在我看到了 2 种方法,我想知道哪一种在性能方面最好:

我可以用'价格'在数据库中寻找价格。上次更新"等于上次更新。

或者我可以获取最后 100 个价格 ID(我们每分钟更新 100 个硬币并在数据库中添加 100 个新行),在我的左侧连接上有一个限制 100 和按"id"DESC 排序。 我知道在左连接上使用 LIMIT 与教义很棘手,但我在这里找到了一个解决方案: 如何限制左连接与原则 (DQL) 的结果 在这里: https://www.colinodell.com/blog/201703/limiting-subqueries-doctrine-2-dql

我想知道执行该查询需要最少的资源量。

当然,我使用的是getArrayResults(),并且正在使用部分和原则缓存。

你对此有何看法? 谢谢!

我也遇到过类似的情况。例如,我运行一个社交商务网络,并希望从企业获取所有follower_ids,以更新它们已执行操作。如果你想要liker_ids,也是一样的,等等。

在此方案中,您只对一列中的值感兴趣(适合您的价格),但基于涉及不同字段(coin_id、上次更新)的查询。为此,我强烈建议使用原则来发送本机SQL查询。它的效率提高了几个数量级,避免了昂贵的学说水合作用等。

我在实体存储库中为您编写了一个示例查询。

<?php
namespace AppEntityRepository;
use DoctrineORMEntityRepository;
use PDO;
class CoinPricesRepository extends EntityRepository
{
public function queryLatestPricesForCoinId(int $coin_id, int $limit)
{
$sql = 'SELECT price FROM coin_prices WHERE coin_id = :coin_id ORDER BY lastupdated DESC LIMIT  = :limit;';
$params['coin_id'] = $coin_id;
$params['limit'] = $limit;
$stmt = $this->getEntityManager()->getConnection()->prepare($sql);
$stmt->execute($params);
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
}

我一直在努力优化我的教义请求,并得到了一些很棒的性能改进,如果有人正在寻找类似的解决方案,我将在这里分享。

首先,尽可能用 where 子句限制左连接 二、使用部分对象 第三,使用数组结果。这实际上改变了一切。

/**
* @return Coins[] Returns an array of Crypto objects
*/
public function findOneByTickerRelationnal($ticker)
{
$em = $this->getEntityManager();
$updatesrepository = $em->getRepository(Updates::class);
$updates = $updatesrepository->findOneBy(['id'=> 1 ]);
// This is where I’ve been doing additional work to limit my left join as much as possible with a ‘with’ on left join
$recentMarkets = $updates->getMarket();
$recentPrices = $updates->getPrice();
$recentSources = $updates->getSources();
$cryptos = $this->createQueryBuilder('c')
->select('partial c.{id, name, ticker}’) //<= use of partial is a plus but you need to know exactly which fields you want
->leftJoin('c.prices', 'p','WITH', 'p.last_updated >= :recentPrices')
->addSelect('partial p.{id, price_usd, daily_volume_usd, change_1h, change_1d, change_7d, rank}')
->leftJoin('c.markets', 'm','WITH', 'm.last_updated >= :recentMarkets')
->addSelect('partial m.{id, cur_supply, market_cap, max_supply}')
->leftJoin('c.sources', 's','WITH', 's.last_updated >= :recentSources')
->addSelect('s')
->where('c.ticker = :ticker')
->setParameter('recentPrices', $recentPrices)
->setParameter('recentMarkets', $recentMarkets)
->setParameter('recentSources', $recentSources)
->setParameter('ticker', $ticker)
->getQuery()
->getArrayResult(); //<=Changes everything 
$results = $cryptos[0];
return $results;
}

最新更新