解决MySQL“无法重新打开表”的错误

我目前正忙于实施一个filter,我需要为每个“标签”生成一个INNER JOIN克劳斯filter。

问题是,在一大堆SQL之后,我有一个包含所有需要进行select的信息的表,但是我需要为每个生成的INNER JOIN

这基本上是这样的:

SELECT * FROM search INNER JOIN search f1 ON f1.baseID = search.baseID AND f1.condition = condition1 INNER JOIN search f2 ON f2.baseID = search.baseID AND f2.condition = condition2 ... INNER JOIN search fN ON fN.baseID = search.baseID AND fN.condition = conditionN 

这工作,但我更喜欢“search”表是暂时的(它可以是几个数量级,如果它不是一个普通的表),但这给了我一个非常恼人的错误: Can't reopen table

有些研究把我带到这个bug报告中,但是在MySQL上的人似乎并不在意这样一个基本特征(多次使用一个表)不能用于临时表。 我遇到了这个问题的很多可伸缩性问题。

是否有任何可行的解决方法,不需要我pipe理大量的临时但非常真实的表格,或者让我维护一个包含所有数据的巨大表格?

亲切的问候,克里斯

[额外]

GROUP_CONCAT答案在我的情况下不起作用,因为我的条件是按特定顺序排列的多个列,所以OR会超出我所需要的AND。 但是,它确实帮助我解决了一个早期的问题,所以现在不再需要临时表或临时表。 我们只是想我们的问题过于通用。 filter的整个应用现在已经从大约一分钟到大约不到四分之一秒。

对,MySQL 文档说:“您不能在同一个查询中多次引用TEMPORARY表。”

下面是一个可以查找相同行的替代查询,尽pipe匹配行的所有条件都不在单独的列中,而是以逗号分隔的列表。

 SELECT f1.baseID, GROUP_CONCAT(f1.condition) FROM search f1 WHERE f1.condition IN (<condition1>, <condition2>, ... <conditionN>) GROUP BY f1.baseID HAVING COUNT(*) = <N>; 

一个简单的解决scheme是复制临时表。 如果表格相对较小,则工作得很好,临时表格通常是这种情况。

就我个人而言,我只是把它做成一张永久的桌子。 您可能需要为这些表创build一个单独的数据库(假设他们需要唯一的名称,因为这些查询可以一次完成),也可以设置合理的权限(您可以设置数据库的权限;在表通配符上设置权限)。

然后你还需要一个清理工作来偶尔删除旧的(MySQL会方便地记住一个表的创build时间,所以你可以用它来解决什么时候需要清理)

我通过创build一个永久的“临时”表并将SPID(对不起,我是从SQL Server域)后缀到表名,来创build一个唯一的表名。 然后创builddynamicSQL语句来创build查询。 如果发生任何不良情况,表格将被丢弃并重新创build。

我希望有一个更好的select。 来吧,MySQL的发展。 “错误”/“function请求”自2008年以来一直开放! 好像所有遇到的“虫子”都在同一条船上。

 select concat('ReviewLatency', CONNECTION_ID()) into @tablename; #Drop "temporary" table if it exists set @dsql=concat('drop table if exists ', @tablename, ';'); PREPARE QUERY1 FROM @dsql; EXECUTE QUERY1; DEALLOCATE PREPARE QUERY1; #Due to MySQL bug not allowing multiple queries in DSQL, we have to break it up... #Also due to MySQL bug, you cannot join a temporary table to itself, #so we create a real table, but append the SPID to it for uniqueness. set @dsql=concat(' create table ', @tablename, ' ( `EventUID` int(11) not null, `EventTimestamp` datetime not null, `HasAudit` bit not null, `GroupName` varchar(255) not null, `UserID` int(11) not null, `EventAuditUID` int(11) null, `ReviewerName` varchar(255) null, index `tmp_', @tablename, '_EventUID` (`EventUID` asc), index `tmp_', @tablename, '_EventAuditUID` (`EventAuditUID` asc), index `tmp_', @tablename, '_EventUID_EventTimestamp` (`EventUID`, `EventTimestamp`) ) ENGINE=MEMORY;'); PREPARE QUERY2 FROM @dsql; EXECUTE QUERY2; DEALLOCATE PREPARE QUERY2; #Insert into the "temporary" table set @dsql=concat(' insert into ', @tablename, ' select e.EventUID, e.EventTimestamp, e.HasAudit, gn.GroupName, epi.UserID, eai.EventUID as `EventAuditUID` , concat(concat(concat(max(concat('' '', ui.UserPropertyValue)), '' (''), ut.UserName), '')'') as `ReviewerName` from EventCore e inner join EventParticipantInformation epi on e.EventUID = epi.EventUID and epi.TypeClass=''FROM'' inner join UserGroupRelation ugr on epi.UserID = ugr.UserID and e.EventTimestamp between ugr.EffectiveStartDate and ugr.EffectiveEndDate inner join GroupNames gn on ugr.GroupID = gn.GroupID left outer join EventAuditInformation eai on e.EventUID = eai.EventUID left outer join UserTable ut on eai.UserID = ut.UserID left outer join UserInformation ui on eai.UserID = ui.UserID and ui.UserProperty=-10 where e.EventTimestamp between @StartDate and @EndDate and e.SenderSID = @FirmID group by e.EventUID;'); PREPARE QUERY3 FROM @dsql; EXECUTE QUERY3; DEALLOCATE PREPARE QUERY3; #Generate the actual query to return results. set @dsql=concat(' select rl1.GroupName as `Group`, coalesce(max(rl1.ReviewerName), '''') as `Reviewer(s)`, count(distinct rl1.EventUID) as `Total Events` , (count(distinct rl1.EventUID) - count(distinct rl1.EventAuditUID)) as `Unreviewed Events` , round(((count(distinct rl1.EventUID) - count(distinct rl1.EventAuditUID)) / count(distinct rl1.EventUID)) * 100, 1) as `% Unreviewed` , date_format(min(rl2.EventTimestamp), ''%W, %b %c %Y %r'') as `Oldest Unreviewed` , count(distinct rl3.EventUID) as `<=7 Days Unreviewed` , count(distinct rl4.EventUID) as `8-14 Days Unreviewed` , count(distinct rl5.EventUID) as `>14 Days Unreviewed` from ', @tablename, ' rl1 left outer join ', @tablename, ' rl2 on rl1.EventUID = rl2.EventUID and rl2.EventAuditUID is null left outer join ', @tablename, ' rl3 on rl1.EventUID = rl3.EventUID and rl3.EventAuditUID is null and rl1.EventTimestamp > DATE_SUB(NOW(), INTERVAL 7 DAY) left outer join ', @tablename, ' rl4 on rl1.EventUID = rl4.EventUID and rl4.EventAuditUID is null and rl1.EventTimestamp between DATE_SUB(NOW(), INTERVAL 7 DAY) and DATE_SUB(NOW(), INTERVAL 14 DAY) left outer join ', @tablename, ' rl5 on rl1.EventUID = rl5.EventUID and rl5.EventAuditUID is null and rl1.EventTimestamp < DATE_SUB(NOW(), INTERVAL 14 DAY) group by rl1.GroupName order by ((count(distinct rl1.EventUID) - count(distinct rl1.EventAuditUID)) / count(distinct rl1.EventUID)) * 100 desc ;'); PREPARE QUERY4 FROM @dsql; EXECUTE QUERY4; DEALLOCATE PREPARE QUERY4; #Drop "temporary" table set @dsql = concat('drop table if exists ', @tablename, ';'); PREPARE QUERY5 FROM @dsql; EXECUTE QUERY5; DEALLOCATE PREPARE QUERY5; 

我能够将查询更改为一个永久表,并为我解决这个问题。 (更改了MicroStrategy中的VLDB设置,临时表types)。