cakephp / orm

[READ-ONLY] A flexible, lightweight and powerful Object-Relational Mapper for PHP, implemented using the DataMapper pattern. This repo is a split of the main code that can be found in https://github.com/cakephp/cakephp

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Standalone] Unnecessary queries

Grafikart opened this issue · comments

I post this issue here since I'm trying to use CakePHP ORM without Cakephp Core.

Is there a way to avoid unnecessary queries ? If I try to get 10 rows from a table CakePHP ORM will do 4 queries to get the structure of my table, even if log is turned off.

Is there a way to prevent this ? If so it would be nice to document it (I tried setting various informations in my Table class but nothing worked so far).
Here is the code I tried and the queries that it generates

ConnectionManager::config('default', [
    .....
    'log' => true
]);
$connection = ConnectionManager::get('default');
$logger = new QueryLogger();
$connection->logger($logger);

$tutoriels = new TutorielsTable(['connection' => $connection]);
$tutoriels->find()->limit(10)->toArray();
var_dump($logger->getQueries());

Array (size=5)
  0 => 
    array (size=3)
      'query' => string 'SHOW FULL COLUMNS FROM `tutoriels`' (length=34)
      'took' => float 2
      'rows' => int 26
  1 => 
    array (size=3)
      'query' => string 'SHOW INDEXES FROM `tutoriels`' (length=29)
      'took' => float 0
      'rows' => int 5
  2 => 
    array (size=3)
      'query' => string 'SELECT * FROM information_schema.key_column_usage AS kcu
            INNER JOIN information_schema.referential_constraints AS rc
            ON (kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME)
            WHERE kcu.TABLE_SCHEMA = 'my_table' AND kcu.TABLE_NAME = 'tutoriels' and rc.TABLE_NAME = 'tutoriels'' (length=301)
      'took' => float 0
      'rows' => int 0
  3 => 
    array (size=3)
      'query' => string 'SHOW TABLE STATUS WHERE Name = 'tutoriels'' (length=42)
      'took' => float 0
      'rows' => int 1
  4 => 
    array (size=3)
      'query' => string 'SELECT Tutoriels.id AS `Tutoriels__id`, Tutoriels.name AS `Tutoriels__name`, Tutoriels.content AS `Tutoriels__content`, Tutoriels.content_markdown AS `Tutoriels__content_markdown`, Tutoriels.tp AS `Tutoriels__tp`, Tutoriels.duration AS `Tutoriels__duration`, Tutoriels.vimeo AS `Tutoriels__vimeo`, Tutoriels.daily AS `Tutoriels__daily`, Tutoriels.youtube AS `Tutoriels__youtube`, Tutoriels.blip AS `Tutoriels__blip`, Tutoriels.video AS `Tutoriels__video`, Tutoriels.video_size AS `Tutoriels__video_size`, Tutoriels.source AS `Tutoriels__source`, Tutoriels.demo AS `Tutoriels__demo`, Tutoriels.slug AS `Tutoriels__slug`, Tutoriels.category_id AS `Tutoriels__category_id`, Tutoriels.created AS `Tutoriels__created`, Tutoriels.comment_count AS `Tutoriels__comment_count`, Tutoriels.online AS `Tutoriels__online`, Tutoriels.premium AS `Tutoriels__premium`, Tutoriels.relative AS `Tutoriels__relative`, Tutoriels.serie AS `Tutoriels__serie`, Tutoriels.user_id AS `Tutoriels__user_id`, Tutoriels.lvl AS `Tutoriels__lvl`, Tutoriels.formation_id AS `Tutoriels__formation_id`, Tutoriels.color AS `Tutoriels__color` FROM tutoriels Tutoriels LIMIT 10' (length=1139)
      'took' => float 0
      'rows' => int 10

You'll need to cache the schema reflection. You can do this in one of a few ways:

  1. Install the cakephp/cache package and enable cacheMetadata in your connection definition.
  2. Create a subclass of Cake\Database\Schema\Collection that caches the results of describe(). The CachedCollection class in the Database package is an example of this. This subclass can be injected into the connection using Connection::schemaCollection($collection).

While the queries look superfluous, they are necessary so the ORM knows which columns can be selected, and the column types when generating insert/update queries.

Ok thanks that was what I was looking for. If someone is looking at this issue here is the solution :

\Cake\Cache\Cache::config('_cake_model_', [
    'className' => 'File',
    'duration' => '+1 hours',
    'path' => 'tmp',
    'prefix' => 'my_app_'
]);

And then enable cache for the connection

ConnectionManager::config('default', [
     ...
    'cacheMetadata' => true
]);