Saat ini saya sibuk menerapkan jenis filter yang saya perlukan untuk membuat klausa INNER JOIN untuk setiap "tag" yang akan difilter.
Masalahnya adalah bahwa setelah sejumlah besar SQL, saya memiliki tabel yang berisi semua informasi yang saya butuhkan untuk membuat pilihan saya, tetapi saya membutuhkannya lagi untuk setiap INNER JOIN yang dihasilkan
Ini pada dasarnya terlihat seperti:
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
Ini berfungsi, tetapi saya lebih suka tabel "pencarian" bersifat sementara (bisa beberapa kali lipat lebih kecil jika itu bukan tabel normal) tetapi itu memberi saya kesalahan yang sangat mengganggu: Can't reopen table
Beberapa penelitian membawa saya ke laporan bug ini tetapi orang-orang di MySQL tampaknya tidak peduli bahwa fitur dasar seperti itu (menggunakan tabel lebih dari sekali) tidak berfungsi dengan tabel sementara. Saya mengalami banyak masalah skalabilitas dengan masalah ini.
Apakah ada solusi yang layak yang tidak mengharuskan saya untuk mengelola banyak tabel sementara tetapi sangat nyata atau membuat saya mempertahankan tabel besar dengan semua data di dalamnya?
Hormat kami, Kris
[tambahan]
Jawaban GROUP_CONCAT tidak berfungsi dalam situasi saya karena kondisi saya terdiri dari beberapa kolom dalam urutan tertentu, itu akan membuat OR dari apa yang saya perlukan menjadi AND. Namun, Itu membantu saya memecahkan masalah sebelumnya jadi sekarang tabel, temp atau tidak, tidak lagi diperlukan. Kami hanya berpikir terlalu umum untuk masalah kami. Seluruh aplikasi filter sekarang telah dibawa kembali dari sekitar satu menit menjadi kurang dari seperempat detik.
sumber
Jawaban:
Jika beralih ke MariaDB (garpu MySQL) dapat dilakukan - gangguan ini telah diperbaiki di sana mulai versi 10.2.1: https://jira.mariadb.org/browse/MDEV-5535 .
sumber
Solusi sederhana adalah menduplikasi tabel sementara. Berfungsi dengan baik jika tabel relatif kecil, yang sering terjadi pada tabel sementara.
sumber
Benar, dokumen MySQL mengatakan: "Anda tidak dapat merujuk ke
TEMPORARY
tabel lebih dari sekali dalam kueri yang sama."Berikut adalah kueri alternatif yang akan menemukan baris yang sama, meskipun semua kondisi baris yang cocok tidak akan berada di kolom terpisah, mereka akan berada dalam daftar yang dipisahkan koma.
SELECT f1.baseID, GROUP_CONCAT(f1.condition) FROM search f1 WHERE f1.condition IN (<condition1>, <condition2>, ... <conditionN>) GROUP BY f1.baseID HAVING COUNT(*) = <N>;
sumber
Saya menyiasatinya dengan membuat tabel permanen "sementara" dan menambahkan SPID (maaf, saya dari tanah SQL Server) ke nama tabel, untuk membuat nama tabel yang unik. Kemudian membuat pernyataan SQL dinamis untuk membuat kueri. Jika terjadi sesuatu yang buruk, tabel akan dijatuhkan dan dibuat ulang.
Saya mengharapkan pilihan yang lebih baik. Ayo, MySQL Devs. 'Permintaan fitur' / 'bug' telah dibuka sejak 2008! Sepertinya semua 'serangga' yang ditemukan ada di perahu yang sama.
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;
sumber
Secara pribadi saya hanya akan menjadikannya meja permanen. Anda mungkin ingin membuat database terpisah untuk tabel-tabel ini (mungkin mereka membutuhkan nama yang unik karena banyak dari query ini dapat dilakukan sekaligus), juga untuk memungkinkan perizinan diatur secara bijaksana (Anda dapat mengatur izin pada database; Anda dapat ' t mengatur izin pada kartu bebas tabel).
Kemudian Anda juga memerlukan pekerjaan pembersihan untuk kadang-kadang menghapus yang lama (MySQL dengan nyaman mengingat saat tabel dibuat, jadi Anda bisa menggunakannya untuk bekerja saat pembersihan diperlukan)
sumber
Saya dapat mengubah kueri menjadi tabel permanen dan ini memperbaikinya untuk saya. (mengubah pengaturan VLDB di MicroStrategy, tipe tabel sementara).
sumber
Anda bisa menyiasatinya dengan membuat tabel permanen, yang akan Anda hapus setelahnya, atau cukup buat 2 tabel temporer terpisah dengan data yang sama
sumber
Berikut adalah dokumen MYSQL tentang masalah ini. Saya menggunakan tabel temporer duplikat seperti beberapa jawaban di atas, namun, Anda mungkin memiliki situasi di mana CTE sesuai!
https://dev.mysql.com/doc/refman/8.0/en/temporary-table-problems.html
sumber