How do you optimize this semi-complex mysql query?

Welcome fellow stop players!

Here's the db schema (it comes down to the appropriate fields) to help illustrate my riddle:

enter image description here

  • The web store has items , and items have item_options .
  • The same item may appear in several categories .
  • categories , items and item_options can be active or inactive (BOOL).

Categories look like this (pay attention to the parent nest where the fruit seeds are inside the seeds):

 id parent_id name active 1 0 Seeds 1 2 1 Vegetable Seeds 1 3 1 Fruit Seeds 0 4 0 Plants 1 5 4 Vegetable Plants 1 6 4 Fruit Plants 1 

What I want is a quick list of all active categories (id, parent_id and name) and the number of active elements in each category containing the active item_options elements.

The query result will look like this:

 id parent_id name item_count 1 0 Seeds 0 2 1 Vegetable Seeds 52 4 0 Plants 0 5 4 Vegetable Plants 103 6 4 Fruit Plants 79 

This request works, but takes ~ 430 ms :

  SELECT c.`id`, c.`parent_id`, c.`name`, (SELECT COUNT(*) FROM `item_categories` AS ic LEFT JOIN `items` AS i ON (i.`id` = ic.`item_id`) LEFT JOIN `item_options` AS io ON (i.`id` = io.`item_id`) WHERE c.`id` = ic.`category_id` AND i.`active` = 1 AND io.`active` = 1 ) AS `item_count` FROM `categories` AS c WHERE c.`active` = 1; 

This following request only takes ~ 55 ms, but does not include top-level categories (where parent_id = 0):

  SELECT c.`id`, c.`parent_id`, c.`name`, COUNT(ic.`item_id`) AS `item_count` FROM `categories` AS c LEFT JOIN `item_categories` AS ic ON (c.`id` = ic.`category_id`) LEFT JOIN `items` AS i ON (i.`id` = ic.`item_id`) LEFT JOIN `item_options` AS io ON (i.`id` = io.`item_id`) WHERE c.`active` = 1 AND i.`active` = 1 AND io.`active` = 1 GROUP BY c.`id`; 

Does anyone see how to speed up the first request or fix the second?

+4
source share
1 answer

ABOUT! It seemed to do it ...

 ( SELECT c.`id`, c.`parent_id`, c.`name`, COUNT(ic.`item_id`) AS `item_count` FROM `categories` AS c LEFT JOIN `item_categories` AS ic ON (c.`id` = ic.`category_id`) LEFT JOIN `items` AS i ON (i.`id` = ic.`item_id`) LEFT JOIN `item_options` AS io ON (i.`id` = io.`item_id`) WHERE c.`active` = 1 AND i.`active` = 1 AND io.`active` = 1 GROUP BY c.`id` ) UNION ( SELECT c.`id`, c.`parent_id`, c.`name`, 0 FROM `categories` AS c WHERE c.`parent_id` = 0 AND c.`active` = 1 ) ORDER BY `parent_id`, `NAME`; 

Does anyone see a better way ?: D

0
source

Source: https://habr.com/ru/post/1436598/


All Articles