MySQL-distinct+;排序查询性能问题 问题
以下查询的运行时间超过30秒,除非:MySQL-distinct+;排序查询性能问题 问题,mysql,performance,Mysql,Performance,以下查询的运行时间超过30秒,除非: 我删除排序(查询),然后让我们检查索引 在bookeditems中是否有关于会议id和项目类型的综合索引 您是否有会议id上的索引?如果它位于复合键中,它是第一个索引吗 你们有关于会议日期时间的聚集索引吗 您是否可以放置一个子查询来获取每个会议id的堆栈顶部,而不是执行distinct 比如: select * from meetings a where datetime = (select max(datetime) from meetings whe
- 我删除排序(查询),然后让我们检查索引
在bookeditems中是否有关于会议id和项目类型的综合索引
您是否有会议id上的索引?如果它位于复合键中,它是第一个索引吗
你们有关于会议日期时间的聚集索引吗
您是否可以放置一个子查询来获取每个会议id的堆栈顶部,而不是执行distinct
比如:
select * from meetings a where datetime = (select max(datetime) from meetings where meetingid = a.meetingid)
您可以使用会议类型上的case语句来获取相同的数据,而不是左键联接吗?我认为index2是不必要的,可以删除;它是index1的前缀。不过,这不会减少查询时间
解释输出显示了真正的罪魁祸首:“使用临时文件,使用文件排序”。有时,您可以通过让MySQL使用用于连接的相同键执行排序来避免这种情况。如果您将index1更改为(meeting_id,datetime),它可能可以这样做。如果您需要在index1中保留项目类型,您可以将其添加为索引中的第三列,或者在查询中包含一个包含所有值的in()子句。您可以尝试帮助优化器首先选择感兴趣的记录(使用
和ORDER by
),然后使用该结果与其他表联接。使用此方法,LIMIT
上的索引可完全用于datetime
和ORDER BY
-子句。此方法如下所示:LIMIT
显著差异:SELECT `meetings`.`id` AS `meeting_id`, `meetings`.`uid` AS meeting_uid, GROUP_CONCAT( DISTINCT CASE bookeditems.item_type WHEN 'SER' THEN bookeditems.id ELSE NULL END ) AS meetings_SERV_ids, GROUP_CONCAT( DISTINCT CASE bookeditems.item_type WHEN 'TRA' THEN bookeditems.id ELSE NULL END ) AS meetings_TRANSP_ids, GROUP_CONCAT( DISTINCT CASE bookeditems.item_type WHEN 'ACC' THEN bookeditems.id ELSE NULL END ) AS meetings_ACCO_ids, GROUP_CONCAT(bookeditems.id) AS meetings_BOOKEDITEMS_ids FROM ( SELECT id FROM meetings ORDER BY `datetime` LIMIT 0, 50 ) filtered_meetings INNER JOIN meetings ON meetings.id = filtered_meetings.id LEFT OUTER JOIN bookeditems ON meeting_uid = bookeditems.meeting_uid GROUP BY meeting_uid
- 我们只加入一次booked items表。在select语句中,我们使用
和GROUP_CONCAT
语句来选择会议组中符合特定条件的所有ID。此外,为了实现这一点,我们需要添加CASE
语句来对代表相同会议的所有行进行分组ng.GROUP BY
这意味着我们可能会获得
、会议服务ID
、会议传输ID
和会议帐户ID
的一系列ID。因此,请记住在处理结果行的客户端代码中使用会议BOOKEDITEMS\u ID
,或等效的方法分解
语句总是会大大减慢查询速度。此外,您还可以删除Order by
表上的别名,因为使用别名会强制MySQL查看表上的所有字段。您还可以粘贴查询的meeting
的输出吗?即:explain
。这将帮助我们了解查询是如何执行的执行计划的外观和使用的索引。请尝试在explain SELECT…
上添加索引。您的表是InnoDB还是MyISAM?@ypercube它已经将其作为索引(我更新了查询,以便会议id现在符合uid);Innodby composite我想你是指包含这两个字段的索引?答:是的,我在meetings表中有关于meeting id的索引。我不知道什么是聚集索引,也不知道如何在MySQL中创建聚集索引-在回答taht之前,我必须先通读一遍。我不明白你所建议的子查询想要实现什么?我怎么不知道是的,如果你是这个意思的话,我可以做一个案例陈述,让bookeditem类型出现在meetings表中…这就是原始查询的功能-我去掉了它以避免复杂性谢谢你的建议-我会尝试它们。问题是datetime并不是唯一可以排序的列,而是唯一可以排序的列我经常重复。此外,为了清楚起见,我更新了问题,将所有表中的索引包括在内。您可以使用MySQL的评测来验证罪魁祸首。运行(项目类型,会议id)
,然后运行您的查询,然后SET profiling=1
,找到您的查询,然后SHOW PROFILES
。最后一个命令将生成一个精细gra表已定义执行查询所需的步骤,以及每个步骤所需的时间。结果是,磁盘上的复制到tmp表的时间=28.3秒…我已将完整结果包含在问题中。谢谢!我在配置中添加了max_heap_table_size=256M和tmp_table_size=256M,这导致“磁盘上的复制到tmp表的时间=28.3秒”替换为“复制到tmp表,2.27”;但我仍然不高兴这是我所能做的一切(当10个ppl同时命中它时,会发生什么情况-你吸收了2.5G的RAM?)。请让我知道您的想法。还有什么我缺少/可以做的吗?理想情况下,我希望不需要临时表?我发现很难相信查询需要“…ORDER BY…LIMIT N”查询经常遇到这个问题。您当前的查询需要MySQL到1)将结果限制为满足WHERE限制的行,2)对所有行进行排序,3)返回前N个结果。诀窍是修改查询或模式,以允许使用相同的索引进行限制和排序。通过这种方式,MySQL可以避免在对所有结果进行排序之前查找所有满足限制的结果。相反,它保留的结果集要小得多,并且能够在处理行时更新这些结果。这并不总是容易的。事实上,这比原始查询(现在排序16秒)需要更长的时间来执行。我已经用createtable定义更新了这个问题,并添加了为什么我想要像我一样的相关表&而不是像你建议的那样在单个字段中串联ID列表。我意识到我比我想象的更像一个noob!对不起,这是我的想法,没有任何测试表和数据。另外,你可以发布一些样本(期望的)输出。我不太明白你想要的输出格式我不太明白你的问题。。。为了让您了解我想要的输出格式,我需要包含解决方案中的SQL语句(20-30个字段)。我想要一个大学就够了吗SHOW PROFILE for query n
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra ------------------------------------------------------------------------------------------------------------------------------------- 1 | SIMPLE | meetings | ALL | NULL | NULL | NULL | NULL | 7483 | Using temporary; Using filesort 1 | SIMPLE | meetings_SERV | ref | meeting_uid,index1 | meeting_uid | 767 | test.meetings.uid | 1 | 1 | SIMPLE | meetings_TRANSP | ref | meeting_uid,index1 | meeting_uid | 767 | test.meetings.uid | 1 | 1 | SIMPLE | meetings_ACCO | ref | meeting_uid,index1 | meeting_uid | 767 | test.meetings.uid | 1 | 1 | SIMPLE | meetings_BOOKEDITEMS | ref | meeting_uid,index1 | meeting_uid | 767 | test.meetings.uid | 1 |
starting 0.000092 checking permissions 0.000003 checking permissions 0.000002 checking permissions 0.000001 checking permissions 0.000001 checking permissions 0.000003 Opening tables 0.000036 System lock 0.000008 init 0.000033 optimizing 0.000005 statistics 0.000035 preparing 0.000019 Creating tmp table 0.000165 executing 0.000004 Copying to tmp table 1.790968 converting HEAP to MyISAM 1.669041 Copying to tmp table on disk 28.32606 Sorting result 0.141737 Sending data 0.000099 end 0.000005 removing tmp table 0.022097 end 0.000014 query end 0.000008 closing tables 0.000017 freeing items 0.000779 logging slow query 0.000004 cleaning up 0.000005
... executing 0.000004 Copying to tmp table 1.790968 Sorting result 0.141737 ...
select * from meetings a where datetime = (select max(datetime) from meetings where meetingid = a.meetingid)
SELECT `meetings`.`id` AS `meeting_id`, `meetings`.`uid` AS meeting_uid, GROUP_CONCAT( DISTINCT CASE bookeditems.item_type WHEN 'SER' THEN bookeditems.id ELSE NULL END ) AS meetings_SERV_ids, GROUP_CONCAT( DISTINCT CASE bookeditems.item_type WHEN 'TRA' THEN bookeditems.id ELSE NULL END ) AS meetings_TRANSP_ids, GROUP_CONCAT( DISTINCT CASE bookeditems.item_type WHEN 'ACC' THEN bookeditems.id ELSE NULL END ) AS meetings_ACCO_ids, GROUP_CONCAT(bookeditems.id) AS meetings_BOOKEDITEMS_ids FROM ( SELECT id FROM meetings ORDER BY `datetime` LIMIT 0, 50 ) filtered_meetings INNER JOIN meetings ON meetings.id = filtered_meetings.id LEFT OUTER JOIN bookeditems ON meeting_uid = bookeditems.meeting_uid GROUP BY meeting_uid
- 我们只加入一次booked items表。在select语句中,我们使用