Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip init of Propel tables in order to boost performance #1909

Closed
wants to merge 5 commits into from
Closed

Skip init of Propel tables in order to boost performance #1909

wants to merge 5 commits into from

Conversation

profuel
Copy link

@profuel profuel commented Oct 26, 2022

When database table map is initialized, originally we create all table classes.
Regular request uses 5-10 tables, so creation of classes is not required.

With this change, only mapping from the qualified table name to a php class name is stored in the database, and the table map class creation happens only on-demand.

@mringler
Copy link
Contributor

Looks like what you are doing is to replace the array holding the qualified names of the table classes by an associative array, which maps the common table name to the qualified name. So this:

[
  0 => '\\Propel\\Tests\\Bookstore\\Book'
]

becomes this:

[
  'book' => '\\Propel\\Tests\\Bookstore\\Book'
]

And later on, you want to use the common name from the key to avoid having to access the static property of the class:

    public function registerTableMapClass(string $tableMapClass): void
    {
        $tableName = $tableMapClass::TABLE_NAME; // <----- this line you want to avoid
        $this->tables[$tableName] = $tableMapClass;

        $tablePhpName = $tableMapClass::TABLE_PHP_NAME; // <----- btw. looks like you just removed this
        $this->addTableByPhpName($tablePhpName, $tableMapClass);
    }

From what I see, this is the only change that might impact runtime, depending on the overhead of accessing the static property.

So far, did I figure it out correctly, is that what you want to do?

If so, can you give me a rough idea of what amount of time can be saved with this?

@profuel
Copy link
Author

profuel commented Oct 26, 2022

Thanks for review @mringler.

Yes, you've got the idea right!

On my local running project, with 320 tables, performance win is 5-50ms. And this is a constant win for every call. So with 10 calls a second, you get 1.2-12 hours CPU time win a day.

Main goal here is to avoid any Propel database mappings, when no DB operations are expected during the call processing.

@mringler
Copy link
Contributor

Ah, nice, sounds good, sorry it took me a bit to get back to you!

In your changes, you removed the possibility to get tables by php name (i.e. 'Bookstore' instead of 'bookstore_schemas.bookstore'), but I don't think we can just get rid of it. I'm pretty sure that when that works, tests will also run through.

To fix this, the loadDatabase.php file would have to also include the php names, which does not work with a simple key-value structure, but is still easy to do. Two possibilities spring to mind:

First is to just write tuples to the file, which include name, php name and class, i.e.

[
  0 => ['bookstore_schemas.book', 'Book', '\\Propel\\Tests\\Bookstore\\Book']
]

and then build the two table maps (name to table class and php name to table class) from that, which should be easy enough.

Alternatively, we could just write the two maps into the file as they are stored internally inside the DatabaseMap class, i.e. something like

$serviceContainer->initDatabaseMaps([
  'default' => [
    'tables' => [
      'bookstore_schemas.book' => '\\Propel\\Tests\\Bookstore\\Book'
    ],
    'tablesByPhpName' => [
      'Book' => '\\Propel\\Tests\\Bookstore\\Book'
    ]
  ]
])

The advantage here is that we don't have to build a second structure, but just insert the maps into the DatabaseMap, and we might be able to use existing code to generate the content of the loadDatabase.php, since we basically just write a dump to that file.

Does that make sense? Let me know what you think about it. Do you favor one of those options, or even a whole other approach?

@profuel
Copy link
Author

profuel commented Oct 28, 2022

No problem with review time at all, thanks Moritz!

Getting table by PHP name works anyway, if you check the function \Propel\Runtime\Map\DatabaseMap::getTableByPhpName

Though I agree, building full tables map make more sense, mentioned above function will return from the first IF much faster.

@mringler
Copy link
Contributor

mringler commented Nov 2, 2022

Hey Andrey, my plan was to ask if you can implement the changes we talked about, and I just wanted to have a quick look at how it would work. So I played around with it a bit, and it worked almost immediately. Now I fell like I grabbed it from you, but at the same time, asking you to do it again seems wrong, too. So I just created a new MR #1910. It'd be great if you have a look at it, maybe do a review, and maybe even check if does make a difference with your large database.

@profuel
Copy link
Author

profuel commented Nov 7, 2022

I will happily close this one, once I test your solution.
thanks @mringler !

@dereuromark
Copy link
Contributor

Alternative PR is open and ready to be merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants