J
J
jest2015-09-03 13:07:52
MySQL
jest, 2015-09-03 13:07:52

How to optimize SQL query for product selection by parameters?

There are 3 tables with a product and its parameters:
Goods: id, article, num (num - the number of options described for the current article)
Parameters (options): id, option
Values ​​(cross): id, goods_id, options_id, value
The article is searched for by a set of options and their values, for example: Weight=15kg, Color=Red and Packaging=Plastic. It is necessary to select only those products that have all these values ​​at the same time, but there are no other values ​​(for example, Width, Length, etc.). If an empty search query is specified, then the system should return those products where there is no value for any parameter.
Now it works like this:

SELECT `goods`.`article` FROM `goods`
WHERE
`goods`.`num`='2' AND 
`goods`.`num`=(SELECT COUNT(*) FROM `cross` WHERE `cross`.`goods_id`=`goods`.`id` AND (
     `options_id`='1' AND `value`='15кг'
     OR
     `options_id`='4' AND `value`='Синий'
));

Where the number in `goods`.`num`='2' is substituted from the code and corresponds to the number of expressions like `options_id`='1' AND `value`='15kg' , which are also automatically generated in the required amount.
The problem is that with a large (tens of thousands or more) number of products and options, the request starts to slow down to a few seconds, which I would like to fix, but I can’t think of a better one. It is highly desirable to perform the search in a single SQL query.
Examples of the
Products tables themselves:
CREATE TABLE `goods` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `article` varchar(127) NOT NULL,
  `num` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `article` (`article`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Товары' AUTO_INCREMENT=11 ;

INSERT INTO `goods` (`id`, `article`, `num`) VALUES
(1, 'Артикул 1', 1), (2, 'Артикул 2', 1),  (3, 'Артикул 3', 1), (4, 'Артикул 4', 1), (5, 'Артикул 5', 1), (6, 'Артикул 6', 2), (7, 'Артикул  7', 2), (8, 'Артикул 8', 3), (9, 'Артикул 9', 3), (10, 'Артикул 10', 4);

Options:
CREATE TABLE `options` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `option` varchar(127) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `option` (`option`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Опции' AUTO_INCREMENT=6 ;

INSERT INTO `options` (`id`, `option`) VALUES
(1, 'Вес'), (2, 'Длина'), (3, 'Ширина'), (4, 'Цвет'), (5, 'Упаковка');

Values:
CREATE TABLE `cross` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `goods_id` int(11) NOT NULL,
  `options_id` int(11) NOT NULL,
  `value` varchar(127) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `goods_id` (`goods_id`,`options_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='Параметры товара' AUTO_INCREMENT=20 ;

INSERT INTO `cross` (`id`, `goods_id`, `options_id`, `value`) VALUES
(1, 1, 1, '15кг'), (2, 2, 2, '120см'), (3, 3, 3, '50см'), (4, 4, 4, 'Синий'), (5, 5, 5, 'Картон'), (6, 6, 1, '15кг'), (7, 6, 4, 'Синий'), (8, 7, 1, '15кг'), (9, 7, 4, 'Красный'), (10, 8, 1, '15кг'), (11, 8, 4, 'Синий'), (12, 8, 5, 'Картон'), (13, 9, 1, '15кг'), (14, 9, 4, 'Белый'), (15, 9, 5, 'Пластик'), (16, 10, 1, '30кг'), (17, 10, 2, '120см'), (18, 10, 3, '50см'), (19, 10, 5, 'Металл');

Answer the question

In order to leave comments, you need to log in

3 answer(s)
R
Rsa97, 2015-09-03
@Rsa97

SELECT `goods`.`article` 
    FROM `goods`
    JOIN `cross` AS `c1` ON `c1`.`goods_id` = `goods`.`id` 
        AND `c1`.`options_id`='1' AND `c1`.`value`='15кг'
    JOIN `cross` AS `c2` ON `c2`.`goods_id` = `goods`.`id` 
        AND `c2`.`options_id`='4' AND `c2`.`value`='Синий'

Well, indexes, of course.

P
Pavel Zhukau, 2015-09-03
@NikesDark

Make an INDEX for the fields you are looking for. We also had such problems at work, the request even happened to be processed for 10 seconds. And of course, do everything through 1 request, there should be 1 request, do not use subqueries.
http://ruhighload.com/post/Working+with+indexes+in+MySQL

T
Talgat Baltasov, 2015-09-03
@talgatbaltasov

Can through Join make, instead of subqueries. And I didn’t understand about num, why is it needed?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question