I have a product with several attributes and each one with several options. The total variations is over 6000. The problem is that rendering takes too long. I've enable Devel module and here are the results:

  • Executed 72 queries in 323.6 ms.
  • Page execution time was 13870.81 ms.
  • Memory used at: devel_boot()=1.44 MB, devel_shutdown()=62.56 MB, PHP peak=69.5 MB.

So I guess there's some bottleneck at the code.

Some notes about the implementation:

  • I need a unique price for each variation.
  • I'm using vanilla Drupal Commerce.

There's any way I could improve performance?

  • There isn't enough to go on here. On a staging system, generate a some profiles to find the slow functions. For example: xdebug.org/docs/profiler
    – cilefen
    Apr 9 '16 at 21:43
  • 3
    If you literally have over 6000 variations of a single product, something is very wrong in your business logic. Try to fix that first, you might just find the rest falls into place
    – Clive
    Apr 9 '16 at 22:56
  • 1
    Check out also the Commerce Pricing Attributes module. It's in pretty bad shape right now, but it should be easier to fix it for your needs and develop on top of it than implement a custom workflow from scratch. I rewrote most of the module for a client where there are be hundreds of different pricing attributes for hundreds of products. IMHO, this is where Commerce lacks features the most. Apr 10 '16 at 7:39
  • 2
    @AramBoyajyan Thanks. I did already check that module and, yes, it's a bit broken. Anyway I really think we should follow DC's way. In the coming days I'll be working on a "alternative" cart module that basically will render a form just like the standard add-to-cart form but without iterating over all variations and all attributes options (basically where the bottleneck is). And maybe a useful contrib module could come out of this. I'll update this question with my findings ;). Apr 10 '16 at 10:10
  • 1
    I love challenges like this ... is your dev site public / could Commerce Guys take a look at it as well? mglaman and I could likely provide some pointers, but your hunch is basically correct - the default attribute system is iterating over all 6,000 variations to determine the attribute widgets to show. On a site where you know every combination is possible, I'd think you could definitely override that logic. Feel free to use the contact form at commerceguys.com to reach out. : ) Apr 10 '16 at 16:37

Didn't find a proper solution to increase the performance or, at least a clean solution. So I decided to create a module that basically holds an alternative view formatter to the "Add to cart" that comes with Drupal Commerce.

You can find the module here: https://www.drupal.org/sandbox/marcofernandes/2705035

Basically it's a "clone" of "Add to cart" view formatter but it avoids iterations over all variations and field options. It's not perfect but it fits my needs (variations for all possible combinations). I'll keep it as a sandbox until it reaches a more mature state (it lacks some validations and, probably it misses some code styling).


Getting a cachegrind/flamegraph would be ideal. There most likely is some code that can be optimized in there.

There's any way I could improve performance?

Most likely yes. If you can wrap the call to the expensive code in a cache call that can be a quick fix. If the data changes quite regularly, and you're ok with data that is a couple of minutes old, you can use HTTPRL's function cache (httprl_call_user_func_array_cache). We use it for some crazy expensive things that take 10 minutes to calculate (stats on every user of our site). The nice thing is it has cache_lifetime_min and cache_lifetime_max; cache_lifetime_min is how long to wait until new data is generated and cache_lifetime_max is how old of data do you want to use. It uses "threading" to make the cache generation part non blocking. Example code below. The first 2 parameters are the same as call_user_func_array(), the last parameter is an array and it controls how the function cache works.

// Don't regenerate until data is 2 minutes old.
// Use data up to 1 day old.
// Function is slow give it 1 minute to run.
// Return NULL if there is no cache data. If FALSE and the cached data doesn't exist, the function will block.
// Store cached data in the cache_custom table/bin. This table needs to exist, or choose to not set it and it defaults to the cache bin.
return httprl_call_user_func_array_cache('function_name', array($uid), array(
  'cache_lifetime_min' => 120,
  'cache_lifetime_max' => 86400,
  'lock_timeout' => 60,
  'return_null_cache_miss' => TRUE,
  'bin' => 'cache_custom',

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.