Loading...
Menu
Cart

Option incompatibility, should we go back?

Talking about database schemas in MySQL and performance is a big story for those nerds who got that in mind,

The new scheme of options that VentoCart introduced over Vanilla opencarts opens the gate for thinking, on the first glance,
ventocart seem too over-engineered and complicated in terms of how it handles the product options, by using only two tables
and the self-joining them to retrieve language entries and option names seem a big headache to the simple way of just having
language and master option group 'eg: Size" seperated than the option it self "Small, Large" however, a bulb got light up
over my head, should we revert back to the simpler times?

To answer that question, on plain intuition the answer is just yes, simpler, less joins and faster,
But behind the scenes, is not that simple, vanilla oc, does fewer joins per function, but uses more functions
therefore, more sql queries, summing them up, it turns out vanilla oc involves left joins of 6 tables in total
while Vento involves only 5 tables.

In other words, we have to put both into the test and measure it in numbers, so a benchmark has to be done.


Benchmarking the new 'product options' query.

The Setup:

  • VentoCart v 4.5.5.5  - 2 Languages, Option name: Benchmark, and options Benchmark 1, Benchmark 2, Benchmark 3. as radio's, had both Language entries and values
  • OpenCart Vanilla v 4.1.0.0: Same setup, 1 option Benchmark, with three radios as above, but had one lanugage only.


Platform:  same machine both running on a Fedora Linux.

                                 Execution Time (seconds)  |   Explanation

  • OpenCart    0.00013399124145508    The old OpenCart approach took 0.00013399124145508 seconds to fetch and process the options data.
  • VentoCart    4.4107437133789E-5    The new VentoCart approach took 4.4107437133789E-5 seconds, which is equivalent to 0.000044107437133789 seconds.

Explanation:

    Scientific Notation: 4.4107437133789E-5 is scientific notation, which represents the number as 4.4107437133789 × 10^-5. This is equivalent to 0.000044107437133789 in standard decimal form.
    OpenCart Time: The old OpenCart method took 0.00013399124145508 seconds, which is a slightly longer execution time than the VentoCart method.
    VentoCart Time: The new VentoCart method took 0.000044107437133789 seconds, which is significantly faster (about 3 times faster than OpenCart) when written out in standard form.

Conclusion:

    The VentoCart approach is faster, taking 0.0000441 seconds compared to OpenCart's 0.000134 seconds.
    The time difference isn't huge, but the VentoCart query is more efficient.
---

Trying to make the Option Table fight fair, We went ahead and in order to lighten up the oc db, we removed from OpenCart All Products, and All other options except the benchmark product - option, while we left VentoCart as is
with its default 7 demo products and 8 option sets and two languages.

Nothing changed in terms of performance that is worth noting

Then we got reminded the fact that Vanilla OpenCart is using two queries for retrieving front end products, we went ahead and optimized that into one single query same way as VentoCart and
we run the bench mark test again.


OpenCart: 4.6014785766602E-5 seconds = 0.00004601478576602 seconds
VentoCart: 4.4107437133789E-5 seconds = 0.000044107437133789 seconds

Insignificant difference with an 'unfair' fight, With-in the margin of error, more runings showed that with the above setups the performance drop to the same level with a single Vanilla opencart option retrival function

"UnOfficial" OpenCarts Function we wrote and used for the second test

    public function getOptions(int $product_id): array
    {
        $start_time = microtime(true);
        $product_option_data = [];

        $product_option_query = $this->db->query("SELECT *
            FROM `" . DB_PREFIX . "product_option` `po`
            LEFT JOIN `" . DB_PREFIX . "option` `o` ON (`po`.`option_id` = `o`.`option_id`)
            LEFT JOIN `" . DB_PREFIX . "option_description` `od` ON (`o`.`option_id` = `od`.`option_id`)
            LEFT JOIN `" . DB_PREFIX . "product_option_value` `pov` ON (`po`.`product_option_id` = `pov`.`product_option_id`)
            LEFT JOIN `" . DB_PREFIX . "option_value` `ov` ON (`pov`.`option_value_id` = `ov`.`option_value_id`)
            LEFT JOIN `" . DB_PREFIX . "option_value_description` `ovd` ON (`ov`.`option_value_id` = `ovd`.`option_value_id`)
            WHERE `po`.`product_id` = '" . (int) $product_id . "'
            AND `od`.`language_id` = '" . (int) $this->config->get('config_language_id') . "'
            AND `ovd`.`language_id` = '" . (int) $this->config->get('config_language_id') . "'
            ORDER BY `o`.`sort_order`, `ov`.`sort_order`");

        // Group the results by product_option_id and map values to 'product_option_value'


        foreach ($product_option_query->rows as $product_option) {
            if (!isset($product_option_data[$product_option['product_option_id']])) {
                $product_option_data[$product_option['product_option_id']] = [
                    'product_option_id' => $product_option['product_option_id'],
                    'option_id' => $product_option['option_id'],
                    'name' => $product_option['name'],
                    'type' => $product_option['type'],
                    'value' => $product_option['value'],
                    'required' => $product_option['required'],
                    'subtract' => $product_option['subtract'],
                    'image' => $product_option['subtract'],
                    'sort_order' => $product_option['sort_order'],
                    'product_option_value' => []
                ];
            }

            // Add the option values
            if ($product_option['product_option_value_id']) {
                $product_option_data[$product_option['product_option_id']]['product_option_value'][] = [
                    'product_option_value_id' => $product_option['product_option_value_id'],
                    'option_value_id' => $product_option['option_value_id'],
                    'name' => $product_option['name'],
                    'price' => $product_option['price'],
                    'image' => $product_option['subtract'],
                    'subtract' => $product_option['subtract'],
                    'price_prefix' => $product_option['price_prefix'],
                    'sort_order' => $product_option['sort_order']
                ];
            }
        }
        $end_time = microtime(true);
        $execution_time = $end_time - $start_time;
        echo 'Execution time: ' . $execution_time . ' seconds' . PHP_EOL;
        print_r($product_option_data);  // Optional: To see the data returned
        die();
        return array_values($product_option_data); // Re-index the array for consistency
    }

 

Therefore, we decided to not revert back to the old OpenCart database schema, and will continue using the new VentoCart approach for better performance.
even if we reverted the difference would lay with in the margin of error, if any.