Problem/Motivation

We have been seeing slow response when viewing orders in a large commerce site via /admin/commerce/orders/{id} with the commerce_log module enabled. Having analysed the issue, it has been attributed to the query that selects the log entries for the order entity using the source entity ID. As there is no index on this field, the query is inefficient and with a modest number of concurrent admin users viewing orders, database resources are quickly exhausted and the site fails.

Proposed resolution

Add an index to the field when the module is enabled.

Provide an update hook for existing installs.

Remaining tasks

Currently working on a patch

Comments

AlanHDev created an issue. See original summary.

alanhdev’s picture

StatusFileSize
new2.06 KB

Adding a patch to add an index to the source_entity_id field in the commerce_log table.

Provides the index for new installs and adds an update hook to fix existing installs.

alanhdev’s picture

Issue summary: View changes
bojanz’s picture

Status: Active » Needs review

Good catch!

One question:

+    $schema['commerce_log']['indexes'] += ['source_entity_id' => ['source_entity_id']];

Wouldn't you want the index to cover both source_entity_id and source_entity_type, since they're always used in tandem?
Something like this:

+    $schema['commerce_log']['indexes'] += ['source_entity' => ['source_entity_id', 'source_entity_type']];
alanhdev’s picture

I'd say yes to that in theory, but in practice the source_entity_type is always going to be 'commerce_order' so it won't offer an improvement, just make the index longer - and we have something like 7 million entries in that table.

bojanz’s picture

That is true only for now. We have an issue for adding logging to payments: #2845321: Add payment logging to orders.
There is no guarantee that sites aren't already using the API for other entity types. For those the index won't be completely precise, because IDs might be shared between entity types.

So i'd prefer #4 if we can prove that it doesn't cause problems for your site.

alanhdev’s picture

No probs. I'll re-roll the patch.

alanhdev’s picture

StatusFileSize
new2.25 KB

Re-rolled the patch to add index on source_entity_id and source_entity_type.

The module could do with some attention to the field lengths. The source_entity_type ends up as default 255 after installation so I've restricted the index size on that field to 32.

alanhdev’s picture

travis-bradbury’s picture

Status: Needs review » Reviewed & tested by the community

Given 330,000 orders and 2,250,000 log entries, queries on commerce_log were often taking over 500ms. With the index this patch provides, it became reasonably fast.

Before:

mysql> explain SELECT commerce_log.log_id AS log_id FROM commerce_log commerce_log    WHERE ((commerce_log.source_entity_id = 123456))      AND (commerce_log.source_entity_type = 'commerce_order')    ORDER BY commerce_log.created DESC;
+----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-----------------------------+
| id | select_type | table        | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra                       |
+----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-----------------------------+
|  1 | SIMPLE      | commerce_log | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 2156164 |     1.00 | Using where; Using filesort |
+----+-------------+--------------+------------+------+---------------+------+---------+------+---------+----------+-----------------------------+
1 row in set, 1 warning (0.01 sec)

mysql> SELECT commerce_log.log_id AS log_id FROM commerce_log commerce_log 
    ->   WHERE ((commerce_log.source_entity_id = 123456)) 
    ->     AND (commerce_log.source_entity_type = 'commerce_order') 
    ->   ORDER BY commerce_log.created DESC;
Empty set (0.86 sec)

After:

mysql> EXPLAIN SELECT commerce_log.log_id AS log_id FROM commerce_log commerce_log    WHERE ((commerce_log.source_entity_id = 123456))      AND (commerce_log.source_entity_type = 'commerce_order')    ORDER BY commerce_log.created DESC;
+----+-------------+--------------+------------+------+---------------+---------------+---------+-------------+------+----------+----------------------------------------------------+
| id | select_type | table        | partitions | type | possible_keys | key           | key_len | ref         | rows | filtered | Extra                                              |
+----+-------------+--------------+------------+------+---------------+---------------+---------+-------------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | commerce_log | NULL       | ref  | source_entity | source_entity | 136     | const,const |    1 |   100.00 | Using index condition; Using where; Using filesort |
+----+-------------+--------------+------------+------+---------------+---------------+---------+-------------+------+----------+----------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> SELECT commerce_log.log_id AS log_id FROM commerce_log commerce_log    WHERE ((commerce_log.source_entity_id = 123456))      AND (commerce_log.source_entity_type = 'commerce_order')    ORDER BY commerce_log.created DESC;
Empty set (0.00 sec)
jsacksick’s picture

The patch looks good to me, though I was sure this was covered by #2907367: Add indexes to important fields for some reason.

I wonder if we could reuse our CommerceContentEntityStorageSchema introduced there. Curious about the 32 limitation on the index, won't that be potentially an issue, considering the column itself doesn't have a 32 character limit?

The update hook should probably take care of updating the entity type definition as well.

jsacksick’s picture

Assigned: Unassigned » jsacksick

Ok you're right, the "entity_type" shouldn't be longer than 32 characters, but I believe we should restrict the column/field itself which removes the need for a limit on the index itself, going to work on a patch that does that and see if I can reuse CommerceContentEntityStorageSchema.

rszrama’s picture

Title: Excessive database load with commerce_log enabled » Improve Order page load times with large amounts of logs
Category: Bug report » Feature request
Priority: Major » Normal

Revising the metadata, preparing for the 2.25 release.

jsacksick’s picture

Status: Reviewed & tested by the community » Needs review
StatusFileSize
new4.1 KB

Ok, so changing the maximum length of an existing base field was more complex than I thought, it took me several attempts to get it right and to get rid of the warnings on the status report page after the update, but I think I got it right this time.

travis-bradbury’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me. I didn't know about the entity type length limit, but fixing it in the table instead of having an index that doesn't match the field makes a lot more sense.

Here's a before and after the patch, showing it's as fast as expected after, same as in #10.

mysql> SELECT commerce_log.log_id AS log_id FROM commerce_log commerce_log WHERE ((commerce_log.source_entity_id = 123456)) AND (commerce_log.source_entity_type = 'commerce_order') ORDER BY commerce_log.created DESC;
Empty set (2.42 sec)

mysql> SELECT commerce_log.log_id AS log_id FROM commerce_log commerce_log WHERE ((commerce_log.source_entity_id = 123456)) AND (commerce_log.source_entity_type = 'commerce_order') ORDER BY commerce_log.created DESC;
Empty set (0.00 sec)

  • jsacksick committed 62d86ad on 8.x-2.x
    Issue #3089661 by AlanHDev, jsacksick, bojanz, tbradbury, rszrama:...
jsacksick’s picture

Status: Reviewed & tested by the community » Fixed

Committed! Thanks for your feedback with testing! I also tried applying the patch myself on an existing project as well to ensure there weren't errors reported in the status report page and it all looked ok!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.