1 mysql execution-plan temporary-tables
请帮助我,删除“使用临时”。我尝试了许多不同的选择,无法摆脱。或排序消失或出现“使用临时”。;(
分类表:
`product_category_multi` (
`m_Id` mediumint(7) NOT NULL,
`prod_Id` smallint(6) unsigned NOT NULL,
`multi_cat` mediumint(7) unsigned NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)
索引表:
ALTER TABLE `product_category_multi`
ADD PRIMARY KEY (`m_Id`),
ADD KEY `multi_cat` (`multi_cat`),
ADD KEY `Id` (`prod_Id`);
Run Code Online (Sandbox Code Playgroud)
示例内容表:
m_Id prod_Id multi_cat
-------+-----------+---------+
1 1 5
2 1 1
3 1 6
4 2 5
5 2 1
6 3 5
7 4 5
8 4 6
Run Code Online (Sandbox Code Playgroud)
产品表:
`shop_product` (
`Id` int(10) unsigned NOT NULL,
`product_article` varchar(20) NOT NULL,
`product_article_main` varchar(20) NOT NULL,
`product_category` int(10) unsigned NOT NULL DEFAULT '0',
`product_name` varchar(255) NOT NULL,
`product_price` int(10) unsigned NOT NULL DEFAULT '0',
`product_active` smallint(1) unsigned NOT NULL DEFAULT '0',
`product_warehouse_temp` enum('0','1') NOT NULL,
`product_top` enum('0','1') NOT NULL,
) ENGINE=MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=0;
Run Code Online (Sandbox Code Playgroud)
索引表:
ALTER TABLE `shop_product`
ADD PRIMARY KEY (`Id`),
ADD KEY `product_name` (`product_name`),
ADD KEY `product_price` (`product_price`),
ADD KEY `product_article_main` (`product_article_main`);
Run Code Online (Sandbox Code Playgroud)
示例内容表:
Id product_article product_article_main product_category product_name product_price product_active product_warehouse_temp product_top
--+-------------------+------------------------+------------------+---------------+----------------+--------------+------------------------+------------+
1 qwe qwe 5 name1 20 1 1 0
2 asd qwe 5 name2 30 1 1 0
3 zxc qwe 5 name3 50 1 0 1
4 wer sdf 6 name4 10 1 1 0
5 sdf sdf 6 name5 20 1 1 0
6 xcv sdf 6 name6 50 1 1 0
7 ert cvb 1 name7 10 1 0 1
8 cvb cvb 1 name8 20 1 1 0
Run Code Online (Sandbox Code Playgroud)
要求:
SELECT
A.*
FROM
(
SELECT prod.Id
FROM shop_product prod
INNER JOIN (
SELECT prod_Id
FROM product_category_multi
WHERE multi_cat = '5'
) AS cat ON cat.prod_Id = prod.Id
WHERE
prod.product_active = '1'
AND prod.product_published_start <= 1471376797
AND prod.product_price = (
select MIN(temp.product_price)
from shop_product temp
where prod.product_article_main=temp.product_article_main
)
ORDER BY prod.product_warehouse_temp DESC, prod.product_top DESC, prod.product_review DESC, prod.Id ASC
LIMIT 0, 20
) B
INNER JOIN shop_product A USING (Id)
Run Code Online (Sandbox Code Playgroud)
显示第 0 - 19 行(共 20 行,查询耗时 0.0899 秒。)
解释:
id select_type table type possible_keys key key_len ref rows Extra
--+---------------+------------------------+-----------+----------------------+-----------------------+-----------+-------------------------------+--------+-------------
1 PRIMARY <derived2> ALL NULL NULL NULL NULL 20
1 PRIMARY A eq_ref PRIMARY PRIMARY 4 B.Id 1
2 DERIVED product_category_multi ref multi_cat,Id multi_cat 3 const 6869 Using temporary; Using filesort
2 DERIVED prod eq_ref PRIMARY PRIMARY 4 product_category_multi.prod_Id 1 Using index condition; Using where
4 DEP. SUBQUERY temp ref product_article_main product_article_main 62 prod.product_article_main 3
Run Code Online (Sandbox Code Playgroud)
这是这个变体,但它不起作用“ORDER BY”子句
SELECT B.*
FROM(
SELECT prod_Id
FROM product_category_multi
WHERE multi_cat = '5'
) cat
INNER JOIN (
SELECT
prod.Id
FROM shop_product prod
WHERE
prod.product_price = (
select MIN(temp.product_price)
from shop_product temp
where prod.product_article_main=temp.product_article_main
)
AND prod.product_active = '1'
AND prod.product_published_start <= '1471268208'
ORDER BY
prod.product_warehouse_temp DESC, prod.product_top DESC
) prod ON cat.prod_Id = prod.id
INNER JOIN shop_product B USING (Id)
Run Code Online (Sandbox Code Playgroud)
显示第 0 - 24 行(共 2296 行,查询耗时 0.0046 秒。)
临时表和文件排序不是坏事;它们是暗示索引不足的症状。
不要在JOIN
什么时候使用子查询来完成这项工作:
SELECT prod.Id
FROM shop_product prod
INNER JOIN (
SELECT prod_Id
FROM product_category_multi
WHERE multi_cat = '5'
) AS cat ON cat.prod_Id = prod.Id
Run Code Online (Sandbox Code Playgroud)
-->
SELECT prod.Id
FROM shop_product prod
INNER JOIN product_category_multi cat
ON cat.prod_Id = prod.Id
WHERE multi_cat = '5'
Run Code Online (Sandbox Code Playgroud)
另一方面,带有聚合的子查询 (MIN(temp.product_price)
)可能比您拥有它的方式更好。
ORDER BY a DESC, b ASC
无法优化。全部应为 ASC 或全部应为 DESC。在您的情况下,您订购的方式可能无关紧要id
,因此请将其更改为 DESC。(可能还有其他问题阻止了此处的任何优化,但这是一个开始。)此索引可能会有所帮助: INDEX(product_warehouse_temp, product_top, product_review, Id)
如果product_category_multi
是多对多映射表,则由于多种原因效率低下。 这是一个更好的方法,它包含了它更好的许多原因。
在有用的地方使用“复合”索引:替换KEY multi_cat(multi_cat)
为(multi_cat, prod_id)
. 替换KEY product_article_main (product_article_main)
为(product_article_main, product_price)
从长远来看,InnoDB 是比 MyISAM 更好的引擎,但我现在不会强调这一点。我认为加快查询是真正的问题。
回到你的问题......目前还不清楚这个查询需要多少个“临时”表。(EXPLAIN FORMAT=JSON SELECT ...
会说。)我建议的索引可能会消除一些临时表,并且可能会加快查询速度。