use*_*096 5 mysql optimization performance select query-optimization
我有一个查询,它有一些子查询(内部选择),我正在尝试找出哪个对性能更好,一个更大的查询或许多更小的查询,我发现很难在差异变化时尝试和计时一直在我的服务器上。
我使用下面的查询一次返回 10 个结果以显示在我的网站上,使用分页(偏移和限制)。
SELECT adverts.*, breed.breed, breed.type, sellers.profile_name, sellers.logo, users.user_level ,
round( sqrt( ( ( (adverts.latitude - '51.558430') * (adverts.latitude - '51.558430') ) * 69.1 * 69.1 ) + ( (adverts.longitude - '-0.0069345') * (adverts.longitude - '-0.0069345') * 53 * 53 ) ), 1 ) as distance,
( SELECT advert_images.image_name FROM advert_images WHERE advert_images.advert_id = adverts.advert_id AND advert_images.main = 1 LIMIT 1) as imagename,
( SELECT count(advert_images.advert_id) from advert_images WHERE advert_images.advert_id = adverts.advert_id ) AS num_photos
FROM adverts
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)
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
Run Code Online (Sandbox Code Playgroud)
从主查询中删除下面的 2 个内部选择,然后在我的 php 循环中,调用 2 个选择 10 次,循环中的每条记录一次,会更好吗?
( SELECT advert_images.image_name FROM advert_images WHERE advert_images.advert_id = adverts.advert_id AND advert_images.main = 1 LIMIT 1) as imagename,
( SELECT count(advert_images.advert_id) from advert_images WHERE advert_images.advert_id = adverts.advert_id ) AS num_photos
Run Code Online (Sandbox Code Playgroud)
据我了解您的内心选择,它们有两个目的:查找关联图像的任何名称,并计算关联图像的数量。您可能可以使用左连接而不是内部选择来实现这两者:
\n\nSELECT \xe2\x80\xa6,\n advert_images.image_name AS imagename,\n COUNT(advert_images.advert_id) AS num_photos,\n \xe2\x80\xa6\nFROM \xe2\x80\xa6\n LEFT JOIN advert_images ON advert_images.advert_id = adverts.advert_id\n\xe2\x80\xa6\nGROUP BY adverts.advert_id\n\xe2\x80\xa6\nLIMIT 0,10\nRun Code Online (Sandbox Code Playgroud)\n\n我还没有尝试过这个,但也许 MySQL 引擎足够聪明,只能对您实际返回的行执行那部分查询。
\n\n请注意,根本无法保证此查询将为给定的图像集返回哪个图像名称。如果您想要可重复的结果,您应该在那里使用一些聚合函数,例如MIN(advert_images.image_name)选择字典顺序的第一个图像。
如果上述方法不起作用,即查询仍将检查表中advert_images计算结果的所有行,那么执行第二个查询可能会更好。但是,您可以尝试避免for循环,而是在单个查询中获取所有这些行:
SELECT advert_images.image_name AS imagename,\n COUNT(advert_images.advert_id) AS num_photos\nFROM advert_images\nWHERE advert_images.advert_id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\nGROUP BY advert_images.advert_id\nRun Code Online (Sandbox Code Playgroud)\n\n此查询中的十个参数对应于您当前生成的结果的十行。请注意,没有相关照片的广告根本不会包含在该结果中。因此,请确保在代码中默认设置num_photos为零和imagenameto 。NULL
实现您尝试执行的操作的另一种方法是使用显式临时内存表:首先选择您感兴趣的结果,然后检索所有关联的信息。
\n\nCREATE TEMPORARY TABLE tmp\nSELECT adverts.advert_id, round(\xe2\x80\xa6) as distance\nFROM adverts\nWHERE (adverts.status = 1) AND (adverts.approved = 1)\n AND (adverts.latitude BETWEEN 51.2692837281 AND 51.8475762719)\n AND (adverts.longitude BETWEEN -0.472015213613 AND 0.458146213613)\nHAVING (distance <= 20)\nORDER BY distance ASC\nLIMIT 0,10;\n\nSELECT tmp.distance, adverts.*, \xe2\x80\xa6\n advert_images.image_name AS imagename,\n COUNT(advert_images.advert_id) AS num_photos,\n \xe2\x80\xa6\nFROM tmp\n INNER JOIN adverts ON tmp.advert_id = adverts.advert_id\n LEFT JOIN breed ON adverts.breed_id = breed.breed_id\n LEFT JOIN sellers ON adverts.user_id = sellers.user_id\n LEFT JOIN users ON adverts.user_id = users.user_id\n LEFT JOIN advert_images ON advert_images.advert_id = adverts.advert_id\nGROUP BY adverts.advert_id\nORDER BY tmp.distance ASC;\n\nDROP TABLE tmp;\nRun Code Online (Sandbox Code Playgroud)\n\n这将确保仅查询所有其他表以获取您当前正在处理的结果。advert_images毕竟,除了您可能需要其中的多行之外,该表没有什么神奇之处。
基于上一段的方法,您甚至可以避免管理临时表,并使用子查询来代替:
\n\nSELECT sub.distance, adverts.*, \xe2\x80\xa6\n advert_images.image_name AS imagename,\n COUNT(advert_images.advert_id) AS num_photos,\n \xe2\x80\xa6\nFROM ( SELECT adverts.advert_id, round(\xe2\x80\xa6) as distance\n FROM adverts\n WHERE (adverts.status = 1) AND (adverts.approved = 1)\n AND (adverts.latitude BETWEEN 51.2692837281 AND 51.8475762719)\n AND (adverts.longitude BETWEEN -0.472015213613 AND 0.458146213613)\n HAVING (distance <= 20)\n ORDER BY distance ASC\n LIMIT 0,10;\n ) AS sub\n INNER JOIN adverts ON sub.advert_id = adverts.advert_id\n LEFT JOIN breed ON adverts.breed_id = breed.breed_id \n LEFT JOIN sellers ON (adverts.user_id = sellers.user_id) \n LEFT JOIN users ON (adverts.user_id = users.user_id) \n LEFT JOIN advert_images ON advert_images.advert_id = adverts.advert_id\nGROUP BY adverts.advert_id\nORDER BY sub.distance ASC\nRun Code Online (Sandbox Code Playgroud)\n\n您再次仅使用表中的数据来确定相关行adverts,并仅连接其他表中所需的行。最有可能的是,中间结果将在内部存储在临时表中,但这由 SQL Server 决定。
| 归档时间: |
|
| 查看次数: |
1820 次 |
| 最近记录: |