我有一个实体“硬币”,其价格与oneToMany相关联。价格每分钟更新一次,有数百万的条目。
我要实现的是一个DQL查询,它将获取迄今为止的最新价格。
现在,我看到了两种实现方法,并且我想知道哪种方法在性能方面最好:
我可以在数据库中查找“价格”。“上次更新”等于上次更新。
或者我可以获取最后100个价格ID(我们每分钟更新100个硬币,并在数据库中添加100个新行),并在我的左侧联接上添加LIMIT 100和ORDER BY'id'DESC。 我知道在带有理论的左联接上使用LIMIT是很棘手的,但是我在这里找到了解决方案: How to limit results of a left-join with Doctrine (DQL) 此处:https://www.colinodell.com/blog/201703/limiting-subqueries-doctrine-2-dql
我想知道执行该查询所需的资源最少。
我当然使用的是getArrayResults(),并且使用的是局部函数和学说缓存。
您对此有何看法? 谢谢!
答案 0 :(得分:1)
我也遇到过类似情况。例如,我运行一个social commerce网络,并希望从企业那里获取所有follower_id,以更新它们是否已执行操作。如果您想要Liker_ids等,就一样。
在这种情况下,您仅对一列中的值(对您的价格)感兴趣,但基于涉及不同字段(coin_id,lastupdated)的查询。为此,我强烈建议您使用主义发送本机SQL查询。它的效率提高了几个数量级,避免了昂贵的理论水合作用等。
我在实体存储库中为您编写了一个示例查询。
<?php
namespace App\EntityRepository;
use Doctrine\ORM\EntityRepository;
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);
}
}
答案 1 :(得分:0)
我一直在优化我的学说要求,并获得了一些很棒的性能改进,如果有人正在寻找类似的解决方案,我将在这里分享。
首先,尽可能用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;
}