我正在对我的应用程序进行一些查询,我需要在我当前的位置上获取最近的商店并首先执行此操作我需要获取所有具有相同名称的项目然后获取它的信息并减少该信息查询。现在我使用IN语句,但由于搜索的项目也是基于列表我需要使用另一个选择这里是我的代码到目前为止:
select *
from product p,
store s,
branches b
where 1 = 1
and b.idproduct = p.idproduct
and p.store = s.idstore
and common_name IN(SELECT p.common_name
FROM shopping_list_content s, product p
WHERE 1 =1
AND s.iditem = p.idproduct
AND s.idlist =$listid)
现在它可以正常运行,但我希望它能比这更快地进行查询。目前,此查询运行速度超过3秒需要3秒以上。如果它不到一秒钟就好多了。我可以使用其他任何选项吗?
答案 0 :(得分:2)
当您编写类似以下内容时,MySQL难以优化子查询:
SELECT *
FROM T
WHERE T.ID (SELECT ID FROM T2);
有时会改写为
SELECT *
FROM T
WHERE EXISTS
( SELECT 1
FROM T2
WHERE T.ID = T2.ID
);
然后在T
中每行执行一次子查询,而如果你写:
SELECT T.*
FROM T
INNER JOIN
( SELECT DISTINCT ID
FROM T2
) T2
ON T2.ID = T.ID;
您的结果集将是相同的,但MySQL将首先使用子查询的结果填充内存表并将其散列在T2.ID上,然后只需要针对{{中的每一行的哈希表查找1}}。
您想要的行为实际上取决于您希望从每个表/子查询中获得多少数据。如果T
中有1百万行,T2
中有10行,那么填充100万行的临时表是没有意义的,只能随后只使用10次,而如果你有T
中的大量行和T
中的少量行实现子查询的额外成本从长远来看将是有益的。
要指出的另一件事(对性能没有影响),您使用的JOIN语法是ANSI 89语法,并且在20多年前被ANSI 92显式JOIN语法取代。虽然针对SQL Server,但我认为this article总结了很好地切换到较新的连接语法的原因。进行最终查询:
T2
N.B。如果您使用的是MySQL 5.6.5或更高版本,则上述大部分内容都不适用。在这个版本中,他们引入了更多Subquery Optimization来解决上述许多问题
答案 1 :(得分:0)
这是您的查询修复使用正确的join
语法:
select *
from product p join
store s
on p.store = s.idstore join
branches b
on b.idproduct = p.idproduct
where p.common_name IN (SELECT p.common_name
FROM shopping_list_content slc join
product p
ON slc.iditem = p.idproduct AND
slc.idlist = $listid
);
假设同一个common_name
未出现在多个产品和上,shopping_list_content
没有重复的行,您可以将其替换为简单的join
:
select *
from product p join
store s
on p.store = s.idstore join
branches b
on b.idproduct = p.idproduct join
shopping_list_content slc
on slc.iditem = p.idproduct and
slc.idlist = $listid;
然而,这些假设可能并非如此。在这种情况下,将子查询更改为使用exists
可能有助于提高性能:
select *
from product p join
store s
on p.store = s.idstore join
branches b
on b.idproduct = p.idproduct
where exists (SELECT 1
FROM shopping_list_content slc join
product p2
on slc.iditem = p2.idproduct AND
slc.idlist = $listid
WHERE p.common_name = p2.common_name
);
对于后一个查询,product(common_name, idproduct)
上的索引以及shopping_list_content(iditem, idlist)
应该会有所帮助。