Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MYSQL查询优化,多个查询或一个大查询_Mysql_Performance_Optimization_Select_Query Optimization - Fatal编程技术网

MYSQL查询优化,多个查询或一个大查询

MYSQL查询优化,多个查询或一个大查询,mysql,performance,optimization,select,query-optimization,Mysql,Performance,Optimization,Select,Query Optimization,我有一个查询,它有一些子查询(内部选择),我正在尝试找出哪一个对性能更好,一个更大的查询或许多更小的查询,我发现很难尝试和计时差异,因为它在我的服务器上一直在变化 我使用下面的查询一次返回10个结果,并使用分页(偏移和限制)显示在我的网站上 我认为MySQL使用文件排序+临时表来执行查询。这就是为什么在大桌子上,你的建议会有更好的效果。通常,执行较小的查询比执行较大的查询更好 避免子查询 据我所知,你的内心选择有两个目的:找到关联图像的任何名称,并计算关联图像的数量。您可能会使用左连接而不是内部

我有一个查询,它有一些子查询(内部选择),我正在尝试找出哪一个对性能更好,一个更大的查询或许多更小的查询,我发现很难尝试和计时差异,因为它在我的服务器上一直在变化

我使用下面的查询一次返回10个结果,并使用分页(偏移和限制)显示在我的网站上


我认为MySQL使用文件排序+临时表来执行查询。这就是为什么在大桌子上,你的建议会有更好的效果。通常,执行较小的查询比执行较大的查询更好

避免子查询 据我所知,你的内心选择有两个目的:找到关联图像的任何名称,并计算关联图像的数量。您可能会使用左连接而不是内部选择来实现这两个目标:

SELECT …,
      advert_images.image_name AS imagename,
      COUNT(advert_images.advert_id) AS num_photos,
      …
FROM …
     LEFT JOIN advert_images ON advert_images.advert_id = adverts.advert_id
…
GROUP BY adverts.advert_id
…
LIMIT 0,10
我还没有尝试过,但也许MySQL引擎足够聪明,可以只对实际返回的行执行这部分查询

请注意,对于给定的一组图像,根本无法保证此查询将返回哪个图像名称。如果你想得到可复制的结果,你应该在那里使用一些聚合函数,例如
MIN(adverd\u images.image\u name)
来选择按字典顺序排列的第一幅图像

单独选择但不循环 如果上述操作不起作用,即查询仍将检查
advert\u images
表中计算结果的所有行,那么执行第二次查询可能会更好。但是,您可以尝试避免
for
循环,而是在单个查询中获取所有这些行:

SELECT advert_images.image_name AS imagename,
       COUNT(advert_images.advert_id) AS num_photos
FROM advert_images
WHERE advert_images.advert_id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
GROUP BY advert_images.advert_id
此查询中的十个参数对应于当前生成的结果的十行。请注意,没有相关照片的广告根本不会包含在结果中。因此,请确保在代码中将
num_photos
默认为零,并将
imagename
默认为
NULL

临时桌 另一种方法是使用显式的临时内存表:首先选择感兴趣的结果,然后检索所有相关信息

CREATE TEMPORARY TABLE tmp
SELECT adverts.advert_id, round(…) as distance
FROM adverts
WHERE (adverts.status = 1) AND (adverts.approved = 1)
  AND (adverts.latitude BETWEEN 51.2692837281 AND 51.8475762719)
  AND (adverts.longitude BETWEEN -0.472015213613 AND 0.458146213613)
HAVING (distance <= 20)
ORDER BY distance ASC
LIMIT 0,10;

SELECT tmp.distance, adverts.*, …
       advert_images.image_name AS imagename,
       COUNT(advert_images.advert_id) AS num_photos,
       …
FROM tmp
     INNER JOIN adverts ON tmp.advert_id = adverts.advert_id
     LEFT JOIN breed ON adverts.breed_id = breed.breed_id
     LEFT JOIN sellers ON adverts.user_id = sellers.user_id
     LEFT JOIN users ON adverts.user_id = users.user_id
     LEFT JOIN advert_images ON advert_images.advert_id = adverts.advert_id
GROUP BY adverts.advert_id
ORDER BY tmp.distance ASC;

DROP TABLE tmp;

同样,您可以仅使用
广告
表中的数据来确定相关行,并仅连接其他表中所需的行。最有可能的是,中间结果将在内部存储在一个临时表中,但这取决于SQL server。

Hi,因为我按距离排序是一个计算字段,所以它使用文件排序,当表较大时会减慢排序速度。因此,是否会对主查询表中的每个记录运行2个内部选择?如果是这样的话,我会认为在结果集上运行2个内部选择会更快。是的,内部选择将在每个rowHi上执行,感谢您的详细回答。我尝试了你提到的第一种方法,通过group by和删除内部选择,但是查询速度比原来慢了很多。临时表听起来确实是个好主意,但是当查询每秒在服务器上运行大约10次时,它能正常工作吗,因为网站非常繁忙?@user1052096,只要临时表方法的两个查询足够接近,影响应该很小。临时表是连接的本地表,因此不会有任何名称冲突。与第二个查询结果的许多列相比,
tmp
表的内存消耗应该很小,因此组合解决方案可能比原始查询使用更少的内存。但是我有另一个想法,我会马上编辑到我的答案中。嗨,MvG,谢谢你使用子查询进行的更新,它确实有效,但我不知道它是否更快。如果我只运行子查询,它将在0.02秒内运行,但是如果我在没有选择广告id的情况下运行子查询,它将在0.01秒的速度下运行两倍。
SELECT advert_images.image_name AS imagename,
       COUNT(advert_images.advert_id) AS num_photos
FROM advert_images
WHERE advert_images.advert_id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
GROUP BY advert_images.advert_id
CREATE TEMPORARY TABLE tmp
SELECT adverts.advert_id, round(…) as distance
FROM adverts
WHERE (adverts.status = 1) AND (adverts.approved = 1)
  AND (adverts.latitude BETWEEN 51.2692837281 AND 51.8475762719)
  AND (adverts.longitude BETWEEN -0.472015213613 AND 0.458146213613)
HAVING (distance <= 20)
ORDER BY distance ASC
LIMIT 0,10;

SELECT tmp.distance, adverts.*, …
       advert_images.image_name AS imagename,
       COUNT(advert_images.advert_id) AS num_photos,
       …
FROM tmp
     INNER JOIN adverts ON tmp.advert_id = adverts.advert_id
     LEFT JOIN breed ON adverts.breed_id = breed.breed_id
     LEFT JOIN sellers ON adverts.user_id = sellers.user_id
     LEFT JOIN users ON adverts.user_id = users.user_id
     LEFT JOIN advert_images ON advert_images.advert_id = adverts.advert_id
GROUP BY adverts.advert_id
ORDER BY tmp.distance ASC;

DROP TABLE tmp;
SELECT sub.distance, adverts.*, …
       advert_images.image_name AS imagename,
       COUNT(advert_images.advert_id) AS num_photos,
       …
FROM ( SELECT adverts.advert_id, round(…) as distance
        FROM adverts
        WHERE (adverts.status = 1) AND (adverts.approved = 1)
          AND (adverts.latitude BETWEEN 51.2692837281 AND 51.8475762719)
          AND (adverts.longitude BETWEEN -0.472015213613 AND 0.458146213613)
        HAVING (distance <= 20)
        ORDER BY distance ASC
        LIMIT 0,10;
     ) AS sub
     INNER JOIN adverts ON sub.advert_id = adverts.advert_id
     LEFT JOIN breed ON adverts.breed_id = breed.breed_id 
     LEFT JOIN sellers ON (adverts.user_id = sellers.user_id) 
     LEFT JOIN users ON (adverts.user_id = users.user_id) 
     LEFT JOIN advert_images ON advert_images.advert_id = adverts.advert_id
GROUP BY adverts.advert_id
ORDER BY sub.distance ASC