Phalcon performance related queries

我只是一个虾纸丫 提交于 2019-11-26 21:41:29

问题


I'm building a REST API for the output of endpoint /projects I have created 2 models:

Projects:

class Projects extends BaseModel
{
    public function initialize()
    {
        $this->hasMany('id', 'Participants', 'projectId');
    }
}

Participants:

class Participants extends BaseModel
{
    public function initialize()
    {
        $this->belongsTo('projectId', 'Projects', 'id');
    }
}

Lets say, I have 10 projects: (1 query)

$results = Projects::find();

I loop through all 10 of them, but I want all Participants too:

foreach($results as $result) {
    echo $result->participants; // 1 query
}

So at the end of the loop Phalcon has made an extra query for each project.

These queries were made by accessing $result->participants while iterating over 10 projects:

SELECT IF(COUNT(*)>0, 1 , 0) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_NAME`='projects'
DESCRIBE `projects`
SELECT `projects`.`id`, `projects`.`title`, `projects`.`client`, `projects`.`color`, `projects`.`start_date`, `projects`.`end_date`, `projects`.`notes`, `projects`.`stateId`, `projects`.`created_at`, `projects`.`updated_at` FROM `projects`
SELECT IF(COUNT(*)>0, 1 , 0) FROM `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_NAME`='project_participants'
DESCRIBE `project_participants`
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0
SELECT `project_participants`.`id`, `project_participants`.`project_id`, `project_participants`.`user_id`, `project_participants`.`user_role_id`, `project_participants`.`user_state_id`, `project_participants`.`updated_at`, `project_participants`.`created_at` FROM `project_participants` WHERE `project_participants`.`project_id` = :0

Question

Is there a way to query the relations before hand, so it will be one query. When I use the Query Builder provided by Phalcon I cannot access ->participants the same way.

Edit

I ended up using Query Builder, namespacing all columns

$builder = $modelsManager->createBuilder();
$builder->columns($columns)
        ->from('Projects')
        ->leftJoin('Participants')
        ->getQuery()
        ->execute();

Columns like so:

Projects.id as projects_id
...
Participants.id as participants_id
Participants.projectId as participants_projectId

Because accessing ->participants on the result created by the Query Builder, did extra queries too.


回答1:


To access ->participants the same way using QueryBuilder, you will have to build join into Query.

Code example could be something like:

$queryBuilder = $this->getDI()->getModelsManager()
    ->createBuilder()
    ->columns(['p.id','participants.*'])
    ->addFrom('Entity\Projects', 'p')
    ->leftJoin('Entity\Participants', 'participants.projectId = p.id', 'participants')
    ->groupBy('p.id, participants.id')
    ->orderBy('p.id ASC');

$resultSet = $queryBuilder->getQuery()->execute();

groupBy() by is used here for making result possibly multi-dimensional.

That kind of query (tested under PgSQL) made Phalcon create some subsequent ResultSet objects of participants pi inside Resultsets for projects p.

You still can iterate through it by using foreach() but after all, I'am not sure it did reduce final query count.

Fireing $result = $resultSet->toArray() made $result['pi'] remain as Resultset, so u should stay cautious on that. You may force it to dump as arrays by defining exact columns in columns() parameters. It has its downside - you will no longer profit from groupBy(), at least on Phalcon 1.3.2 and PHP 5.5.3 im running here.




回答2:


There is a great library for eager loading on phalcon.

stibiumz phalcon eager loading

That library solves the N + 1 queries for relationships. It is already included on the phalcon incubator. I'm using it on production already.

What it does is create a query using the IN clause and filling the models with the results.

On a has many it does:

SELECT * FROM main
SELECT * FROM related WHERE x.id IN (results from the previous resultset)


来源:https://stackoverflow.com/questions/28755079/phalcon-performance-related-queries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!