2008-12-05 75 views
61

我目前正在忙於實施一個過濾器,我需要爲每個「標記」過濾器生成一個INNER JOIN clausse。解決MySQL「無法重新打開表格」錯誤

的問題是一大堆SQL後,我有一個包含我需要讓我選擇的所有信息的表,但我又需要它的每個生成的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 

這工作,但我更希望「搜索」表是臨時的(也可以是幅度小几個數量級,如果它不是一個正常的表),但給了我一個非常惱人的錯誤:Can't reopen table

有些研究將我帶到this bug report,但在MySQL的人似乎並不在乎這種基本功能(多次使用表)不適用於臨時表。我遇到了這個問題的很多可伸縮性問題。

是否有任何可行的解決方法,不需要我管理大量臨時但非常真實的表格,或者讓我維護一個包含所有數據的巨大表格?

親切的問候,克里斯

[附加]

的GROUP_CONCAT答案並不在我的情況下工作,因爲我的條件是特定的順序多列,我需要的是與運算它將使手術室出來的。但是,它確實幫助我解決了早期的問題,所以現在不再需要表格,溫度或不是。我們只是想我們的問題過於通用。過濾器的整個應用現在已經從大約一分鐘恢復到不到四分之一秒。

+1

我在使用UNION的相同查詢中使用兩次臨時表時遇到同樣的問題。 – 2010-10-21 17:11:09

回答

32

對,MySQL docs說:「在同一查詢中,您不能多次引用TEMPORARY表。」

下面是一個應該找到相同行的替代查詢,但匹配行的所有條件不會位於單獨的列中,它們將位於以逗號分隔的列表中。

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

這實際上並沒有解決我手邊的問題,但它確實使我能夠簡化導致它的問題,從而否定了對臨時表的需求。謝謝! – Kris 2008-12-08 09:53:56

3

就我個人而言,我只是把它作爲一個永久的表。您可能需要爲這些表創建一個單獨的數據庫(假設他們需要唯一的名稱,因爲這些查詢可以一次完成),還可以設置合理的權限(您可以設置數據庫的權限;您可以'在表通配符上設置權限)。

然後,你想也需要一個清理作業偶爾刪除舊的(MySQL的方便記得有一個表的創建時間,所以你可以只用它來制定出了需要清理時)

+4

臨時表具有極大的優勢,您可以同時運行多個查詢。這對於永久表是不可能的。 – Pacerier 2015-05-04 07:14:10

1

我能夠將查詢更改爲永久表,併爲我解決了這個問題。 (更改MicroStrategy中的VLDB設置,臨時表類型)。

71

一個簡單的解決方案是複製臨時表。如果表格相對較小,則工作良好,臨時表格通常是這種情況。

+5

實際上應該是選擇的答案,因爲這可以回答問題,而不會四處走動。 – dyesdyes 2014-08-25 16:32:05

+1

關於* how *會重複表格的任何建議? (我的意思是一種複製方式不重複查詢) – 2016-03-02 12:40:25

3

我通過創建一個永久的「臨時」表並將後綴SPID(對不起,我是從SQL Server域)添加到表名中來創建獨特的表名。然後創建動態SQL語句來創建查詢。如果發生任何不良情況,表格將被丟棄並重新創建。

我希望有更好的選擇。來吧,MySQL的發展。 'bug'/'功能請求'自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;