簡體   English   中英

有人可以幫我優化這個mysql語句嗎?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM