【问题标题】:Enhancing performance when applying multiple joins in mysql在 mysql 中应用多个连接时提高性能
【发布时间】:2016-02-10 10:31:39
【问题描述】:

我有 3 张桌子:

Nutritions_facts 表是静态表,包含所有 Nutrition Nutrition_id 和 Nutrition_ename Products_info 表,其中包含产品信息,列是 product_id、product_ename、brand product_nutrition_facts 这是将产品与其营养成分及其价值联系起来的中介表。结构是 product_id, Nutrition_id, Nutrition_value .. 每个产品可以有 1 行或更多行,具体取决于它具有的营养成分的数量。 这是一个真实的测试示例

Nutrition_facts 表

 nutrition_id |nutrition_ename
       1 | caloreis    
       2 | fat    
       3 | sugar    
       4 | salt

Products_info 表

product_id| product_ename           | brand   
    1 | Nutella Hazelnut Cocoa | Nutella    
    2 | Nutella Jar            | Nutella

product_nutrition_facts 表

product_id | nutrition_id | nutrition_value
     1 |            1 |             200
     1 |            2 |              15
     1 |            3 |               2
     1 |            4 |              11
     2 |            1 |             200
     2 |            2 |              15
     2 |            3 |              12
     2 |            4 |              11

我需要查询返回糖值小于或等于 15 且盐值小于或等于 140 的产品名称

我构建了一个返回正确值的查询,但它需要很长时间来处理。有人可以建议修改以提高性能吗..

SELECT DISTINCT p.product_id, p.brand, p.e_name, p.image_low
FROM products_info p
JOIN product_nutrition_facts pn ON p.product_id = pn.product_id
WHERE p.brand =  'AL MARAI'
AND (
(
p.product_id
IN (

SELECT product_id
FROM product_nutrition_facts pn
WHERE pn.nutrition_id =3
AND pn.nutrition_value <=15
)
 )
 AND (
 p.product_id
IN (

SELECT product_id
FROM product_nutrition_facts pn
WHERE pn.nutrition_id =4
AND pn.nutrition_value <=140
)
)
)
AND (
pn.nutrition_id =3
OR pn.nutrition_id =4
)

编辑

 CREATE TABLE `products_info` (
 `product_id` int(11) NOT NULL AUTO_INCREMENT,
 `image_low` varchar(400) DEFAULT NULL,
  `e_name` varchar(200) DEFAULT NULL, 
 PRIMARY KEY (`product_id`),
 UNIQUE KEY `product_id_UNIQUE` (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=249292 DEFAULT CHARSET=utf8


CREATE TABLE `product_nutrition_facts` (
 `prod_nut_id` int(11) NOT NULL AUTO_INCREMENT,
 `product_id` int(11) DEFAULT NULL,
 `nutrition_id` int(11) DEFAULT NULL,
 `nutrition_value` varchar(25) DEFAULT NULL,
 `unit_id` int(11) DEFAULT NULL,
 `parent` int(11) DEFAULT NULL,
 `serving_size` varchar(145) DEFAULT NULL,
 `serving_size_unit` int(11) DEFAULT NULL,
 `no_nutrition_facts` int(11) NOT NULL,
 `added_by` varchar(145) DEFAULT NULL,
 `last_update` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 `inserted_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
 `updated_by` varchar(150) NOT NULL,
 PRIMARY KEY (`prod_nut_id`),
 UNIQUE KEY `prod_nut_id_UNIQUE` (`prod_nut_id`),
 KEY `nutrition_id_fk_idx` (`nutrition_id`),
 KEY `unit_Fk_idx` (`unit_id`),
 KEY `unit_fk1_idx` (`serving_size_unit`),
 KEY `product_idFK` (`product_id`)
) ENGINE=InnoDB AUTO_INCREMENT=580809 DEFAULT CHARSET=utf8

 CREATE TABLE `nutrition_facts` (
 `nutrition_id` int(11) NOT NULL AUTO_INCREMENT,
 `nutrition_aname` varchar(145) DEFAULT NULL,
 `nutrition_ename` varchar(145) DEFAULT NULL,
 `alternative_name` varchar(145) DEFAULT NULL,
  `unit` varchar(8) NOT NULL,
 `daily_value` int(11) NOT NULL,
 `nut_order` int(2) NOT NULL,
 `is_child` int(1) NOT NULL,
 `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
 PRIMARY KEY (`nutrition_id`)
 ) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8

【问题讨论】:

  • 添加表描述show create table Nutritions_factsshow create table Products_infoshow create table product_nutrition_facts
  • @MaxP。我添加了它们,但 products_info 表非常大,所以我只放了一部分..

标签: mysql performance join multiple-tables


【解决方案1】:

尝试添加索引product_nutrition_facts (nutrition_id,nutrition_value,product_id)product_nutrition_facts (product_id,nutrition_id,nutrition_value)products_info (brand)并执行查询

SELECT p.*
FROM products_info p
join product_nutrition_facts pn1 on
  pn1.product_id=p.product_id
  AND pn1.nutrition_id=3
  AND pn1.nutrition_value<=15
join product_nutrition_facts pn2 on
  pn2.product_id=p.product_id
  AND pn2.nutrition_id=4
  AND pn2.nutrition_value<=140
where
  p.brand =  'AL MARAI'

【讨论】:

    【解决方案2】:

    IN ( SELECT ... ) -- 没有优化好;变成JOIN(正如 Max 建议的那样)

    “过度归一化”——Nutrition_facts可以消除;只需使用 Nutrition_names 代替 Nutrition_id。

    【讨论】:

      猜你喜欢
      • 2013-05-18
      • 1970-01-01
      • 2016-11-05
      • 2012-06-16
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 1970-01-01
      相关资源
      最近更新 更多