2008-12-05 32 views
61

Tôi hiện đang bận triển khai bộ lọc loại mà tôi cần tạo một mệnh đề INNER JOIN cho mỗi "thẻ" để lọc.Bắt gặp lỗi MySQL "Không thể mở lại bảng"

Vấn đề là sau khi một bó toàn bộ SQL, tôi có một bảng có chứa tất cả thông tin mà tôi cần phải thực hiện lựa chọn của tôi, nhưng tôi cần nó một lần nữa cho mỗi INNER tạo THAM GIA

này về cơ bản trông giống như:

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 

này hoạt động nhưng tôi rất muốn "tìm kiếm" bảng chỉ là tạm thời (nó có thể được vài bậc nhỏ hơn nếu nó không phải là một bảng bình thường) nhưng điều đó mang lại cho tôi một lỗi rất khó chịu: Can't reopen table

Một số nghiên cứu dẫn tôi đến this bug report nhưng những người ở trên MySQL dường như không quan tâm rằng một tính năng cơ bản như vậy (sử dụng một bảng nhiều lần) không hoạt động với các bảng tạm thời. Tôi đang gặp rất nhiều vấn đề về khả năng mở rộng với vấn đề này.

Có cách giải quyết khả thi nào không yêu cầu tôi quản lý nhiều bảng tạm thời nhưng rất thực hay làm cho tôi duy trì một bảng lớn với tất cả dữ liệu trong đó?

liên quan

Kind, Kris

[thêm]

Câu trả lời GROUP_CONCAT không hoạt động trong hoàn cảnh của tôi vì điều kiện của tôi là nhiều cột theo thứ tự cụ thể, nó sẽ làm cho ORS ra khỏi những gì tôi cần phải ANDs . Tuy nhiên, nó đã giúp tôi giải quyết một vấn đề trước đó vì vậy bây giờ bảng, tạm thời hay không, không còn cần thiết. Chúng tôi đã suy nghĩ quá chung chung cho vấn đề của chúng tôi. Toàn bộ ứng dụng của các bộ lọc hiện đã được đưa trở lại từ khoảng một phút đến dưới một phần tư giây.

+1

Tôi đã gặp sự cố tương tự khi sử dụng bảng tạm thời hai lần trong cùng một truy vấn sử dụng UNION. –

Trả lời

32

Phải, MySQL docs nói: "Bạn không thể tham chiếu bảng TEMPORARY nhiều lần trong cùng một truy vấn".

Đây là truy vấn thay thế nên tìm cùng hàng, mặc dù tất cả các điều kiện của hàng phù hợp sẽ không nằm trong các cột riêng biệt, chúng sẽ nằm trong danh sách được phân cách bằng dấu phẩy.

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

Điều này đã không thực sự giải quyết vấn đề của tôi trong tầm tay, nhưng nó đã cho phép tôi để đơn giản hóa vấn đề gây ra nó, do đó phủ nhận sự cần thiết cho sự cám dỗ. Cảm ơn! – Kris

3

Cá nhân tôi chỉ làm bảng vĩnh viễn. Bạn có thể muốn tạo một cơ sở dữ liệu riêng biệt cho các bảng này (có lẽ chúng sẽ cần các tên duy nhất vì nhiều truy vấn này có thể được thực hiện cùng một lúc), cũng cho phép thiết lập một cách hợp lý (Bạn có thể đặt quyền trên cơ sở dữ liệu; t đặt quyền trên bảng ký tự đại diện bảng).

Sau đó, bạn cũng sẽ cần một công việc dọn dẹp để loại bỏ những cái cũ thỉnh thoảng (MySQL thuận tiện nhớ lại thời gian một bảng đã được tạo ra, vì vậy bạn chỉ có thể sử dụng để làm việc ra khi một dọn dẹp được yêu cầu)

+4

Bảng tạm thời có lợi thế cực đoan mà bạn có thể có nhiều truy vấn chạy đồng thời. Điều này là không thể với bảng vĩnh viễn. – Pacerier

1

tôi đã có thể thay đổi truy vấn thành một bảng vĩnh viễn và điều này đã sửa nó cho tôi. (thay đổi cài đặt VLDB trong MicroStrategy, loại bảng tạm thời).

71

Một giải pháp đơn giản là sao chép bảng tạm thời. Hoạt động tốt nếu bảng tương đối nhỏ, thường là trường hợp với các bảng tạm thời.

+5

Thực sự là câu trả lời được chọn vì câu trả lời này không giải quyết được vấn đề. – dyesdyes

+1

bất kỳ lời khuyên nào về * cách * bạn sao chép bảng? (Tôi có nghĩa là một cách sao chép không lặp lại truy vấn) –

+6

Ngay cả khi bảng tạm thời là lớn, bộ nhớ cache của mysql sẽ giúp bạn ra ngoài. Theo như việc sao chép từ một bảng tạm thời sang bảng khác, một "TẠO TẠM TỪ 2 TỪ THÍCH TỪ * TỪ" TẠO TẠO TẠO TẠM TẠO "TỪNG TỪ" nên làm điều đó. – AS7K

3

Tôi đã giải quyết vấn đề này bằng cách tạo bảng tạm thời "tạm thời" và điền SPID (xin lỗi, tôi đến từ miền SQL Server) vào tên bảng, để tạo tên bảng duy nhất. Sau đó tạo các câu lệnh SQL động để tạo các truy vấn.Nếu bất cứ điều gì xấu xảy ra, bảng sẽ bị xóa và tái tạo.

Tôi hy vọng có một lựa chọn tốt hơn. Thôi nào, MySQL Devs. Yêu cầu tính năng 'lỗi'/'đã được mở từ năm 2008! Có vẻ như tất cả các 'lỗi' đã gặp phải trong cùng một chiếc thuyền.

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; 
+0

Hy vọng rằng bây giờ chúng ta có Oracle tiếp quản các triều đại, cô ấy có thể cho MySQL một sự thúc đẩy tốt. – Pacerier

+2

* sigh * Tôi nghi ngờ nó: ( – beeks

+3

Một _sigh_ lớn tháng Bảy năm 2016, và lỗi bảng tạm thời này vẫn không cố định.Tôi có lẽ sẽ đến với một số loại số thứ tự nối với một tên bảng vĩnh viễn (tôi từ Oracle đất đai) để vượt qua vấn đề này. – TheWalkingData

Các vấn đề liên quan