[英]Can Someone Help me Optimize this mysql statement?
我有一個表用於在我的數據庫中構建組。 該表包含組名和ID的列表。 我有另一個有用戶的表,第三個表顯示了這些關系。 (userid,groupid)。
情況就是這樣,我需要創建一個屬於特定子組的用戶ID列表。 因此,例如,我想要第1組,第3組和第8組中的所有用戶。這很直接。 它變得更復雜,我可能需要列出第1,3和8組,或者1,2和8的所有用戶的列表。然后我可能需要排除符合該條件的用戶,但也在組中27。
所以我有一個動態創建查詢的腳本,使用適用於某一點的子查詢。 我有兩個問題。 我認為我沒有正確處理不合適的部分,因為按照我的標准,最終它只是有點懸而未決。 (我認為這是我使用子選擇而不是連接的結果,但我無法弄清楚如何使用連接來構建它。)
以下是帶有4個ANDed OR組和2個NOT子句的查詢示例。
如果有更好的方法來優化此操作,請告訴我。 (我可以在PHP中處理它的動態構建)
如果我需要澄清任何內容或提供更多細節,請告訴我。
select * from users_table where username IN
(
select user_id from
(
select distinct user_id from group_user_map where user_id in
(
select user_id from
(
select * from
(
select count(*) as counter, user_id from
(
(
select distinct(user_id) from group_user_map where group_id in (2601,119)
)
union all
(
select distinct(user_id) from group_user_map where group_id in (58,226)
)
union all
(
select distinct(user_id) from group_user_map where group_id in (1299,525)
)
union all
(
select distinct(user_id) from group_user_map where group_id in (2524,128)
)
)
thegroups group by user_id
)
getall where counter = 4
)
getuserids
)
and user_id not in
(
select user_id from group_user_map where group_id in (2572)
)
)
biggergroup
);
注意,查詢的第一部分是將id與用戶名進行比較。 這是因為我將用戶名存儲為另一個表中的id。 (這整個事情是兩個完全不同的數據庫之間的鏈接)。
(另外,如果看起來我有任何額外的子查詢,那就是試圖強制mysql首先評估內部查詢。)
謝謝。
亞倫。
如果發布表結構和一些示例數據,將更容易理解您的問題。 但是這里有一些基於您當前查詢的建議,您可以使用它們。
這些查詢會減少您正在使用的子查詢的數量。 其中一個明顯的變化是它獲取每個組的user_id
列表的方式不同:
select user_id
from group_user_map
where group_id in (2601,119)
union all
select user_id
from group_user_map
where group_id in (58,226)
union all
select user_id
from group_user_map
where group_id in (1299,525)
union all
select user_id
from group_user_map
where group_id in (2524,128);
這使用UNION ALL
,它將列出所有user_id
即使它們是重復的。 一旦你有了user_id
的這個列表,你就可以通過應用count(distinct user_id)
獲得count
,並使用HAVING
子句來查找那些有4次出現的子句。
首先,您可以在WHERE
子句中將當前查詢合並到以下版本:
select *
from users_table
where username IN (select user_id
from
(
select user_id
from group_user_map
where group_id in (2601,119)
union all
select user_id
from group_user_map
where group_id in (58,226)
union all
select user_id
from group_user_map
where group_id in (1299,525)
union all
select user_id
from group_user_map
where group_id in (2524,128)
) thegroups
where user_id not in (select user_id
from group_user_map
where group_id in (2572))
group by userid
having count(distinct userid) = 4);
或者您可以在您加入的子查詢中的WHERE
子句中使用查詢:
select ut.*
from users_table ut
inner join
(
select user_id
from
(
select user_id
from group_user_map
where group_id in (2601,119)
union all
select user_id
from group_user_map
where group_id in (58,226)
union all
select user_id
from group_user_map
where group_id in (1299,525)
union all
select user_id
from group_user_map
where group_id in (2524,128)
) thegroups
where user_id not in (select user_id
from group_user_map
where group_id in (2572))
group by userid
having count(distinct userid) = 4
) biggergroup
on ut.username = biggergroup.user_id;
避免用於IN子句的子選擇: -
SELECT *
FROM users_table
INNER JOIN
(
SELECT Sub1.user_id
FROM (
SELECT COUNT(*) AS counter, user_id
FROM (
SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (2601,119)
UNION ALL
SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (58,226)
UNION ALL
SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (1299,525)
UNION ALL
SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (2524,128)
) thegroups
GROUP BY user_id
HAVING counter = 4
) Sub1
LEFT OUTER JOIN (SELECT user_id FROM group_user_map WHERE group_id IN (2572)) Sub2
ON group_user_map.user_id = Sub2.user_id
WHERE Sub2.user_id IS NULL
) Sub3
ON users_table.username = Sub3.user_id
或者避免使用COUNT來檢查所有4個表中是否存在用戶ID,而是使用內部聯接
SELECT *
FROM users_table
INNER JOIN
(
SELECT Sub1.user_id
FROM (
SELECT z.user_id
FROM (
SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (2601,119)) z
INNER JOIN
(SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (58,226)) y ON z.user_id = y.user_id
INNER JOIN
(SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (1299,525)) x ON z.user_id = x.user_id
INNER JOIN
(SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (2524,128)) w ON z.user_id = w.user_id
) Sub1
LEFT OUTER JOIN (SELECT user_id FROM group_user_map WHERE group_id IN (2572)) Sub2
ON group_user_map.user_id = Sub2.user_id
WHERE Sub2.user_id IS NULL
) Sub3
ON users_table.username = Sub3.user_id
稍微清理第二個查詢
SELECT *
FROM users_table
INNER JOIN
(
SELECT z.user_id
FROM (SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (2601,119)) z
INNER JOIN (SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (58,226)) y
ON z.user_id = y.user_id
INNER JOIN (SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (1299,525)) x
ON z.user_id = x.user_id
INNER JOIN (SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (2524,128)) w
ON z.user_id = w.user_id
LEFT OUTER JOIN (SELECT user_id FROM group_user_map WHERE group_id IN (2572)) Sub2
ON z.user_id = Sub2.user_id
WHERE Sub2.user_id IS NULL
) Sub3
ON users_table.username = Sub3.user_id
在下面的評論中使用您的SQL,它可以清理到: -
select SQL_NO_CACHE id
from users_table
INNER JOIN ( SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (0, 67) ) ij1
ON users_table.username = ij1.user_id
LEFT OUTER JOIN ( SELECT user_id FROM group_user_map WHERE group_id IN (0) ) Sub2
ON users_table.username = Sub2.user_id
WHERE Sub2.user_id IS NULL
以同樣的方式清理我的SQL: -
SELECT users_table.*
FROM users_table
INNER JOIN (SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (2601,119)) z ON users_table.username = z.user_id
INNER JOIN (SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (58,226)) y ON users_table.username = y.user_id
INNER JOIN (SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (1299,525)) x ON users_table.username = x.user_id
INNER JOIN (SELECT distinct(user_id) FROM group_user_map WHERE group_id IN (2524,128)) w ON users_table.username = w.user_id
LEFT OUTER JOIN (SELECT user_id FROM group_user_map WHERE group_id IN (2572)) Sub2 ON users_table.username = Sub2.user_id
WHERE Sub2.user_id IS NULL
刪除子選擇並直接進行連接(可能有幫助或阻礙,懷疑它將取決於每組group_id記錄有多少重復的user_id記錄)
SELECT DISTINCT users_table.*
FROM users_table
INNER JOIN group_user_map z ON users_table.username = z.user_id AND z.group_id IN (2601,119)
INNER JOIN group_user_map y ON users_table.username = y.user_id AND y.group_id IN (58,226)
INNER JOIN group_user_map x ON users_table.username = x.user_id AND x.group_id IN (1299,525)
INNER JOIN group_user_map w ON users_table.username = w.user_id AND w.group_id IN (2524,128)
LEFT OUTER JOIN group_user_map Sub2 ON users_table.username = Sub2.user_id AND Sub2.group_id IN (2572)
WHERE Sub2.user_id IS NULL
當你說“我想要第1,3和8組中的所有用戶”然后寫下時,你的意思並不完全清楚
select distinct(user_id) from group_user_map where group_id in (58,226)
因為英語建議您希望所有三個組中的用戶,但SQL會為您提供位於任意一個組中的用戶。 所以你需要更清楚你想要什么。
有點難以相信你正試圖找到所有4個超級組中的用戶,每個超級組只有2組。 它讓我懷疑你在做什么以及為什么。
根據你真正想要遇到的東西,我可以想到幾種不同的方法。 顯然,最簡單的方法是將其分解為多個查詢並將結果合並到代碼中。 如果組表不是太大,您可以自動加入組表,但它可能太大而無法加入3次。 使用NOT EXISTS
可能會比使用NOT IN
獲得更好的性能,但可能不會。 您可以嘗試使用CASE
函數進一步利用聚合函數來計算中間表中的成功值,但這變得非常瘋狂。 更有可能的是,您最好重新修改數據結構。
我在現有解決方案中看到的主要問題是您創建的大量臨時表。 一般來說,你需要一個臨時表來做一些復雜的事情,所以我會集中精力將它限制在兩個表中,每個表都小於關系表。
這是正確的查詢
select * from users_table where username IN
(
(select distinct(user_id) from group_user_map where group_id in (2601,119)) a
inner join
(select distinct(user_id) from group_user_map where group_id in (58,226)) b
on a.user_id = b.user_id inner join
(select distinct(user_id) from group_user_map where group_id in (1299,525)) c
on a.user_id = c.user_id inner join
(select distinct(user_id) from group_user_map where group_id in (2524,128)) d
on a.user_id = d.user_id
) and user_id not in (select user_id from group_user_map where group_id in (2572))
而不是聯合所有,最后過濾有4的計數器,我用相交替換。 請檢查結果是否正確並且運行速度快?
VINIT
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.