簡體   English   中英

如何確定 MySQL 查詢時間的非線性增加?

[英]How do I identify non-linear increase in time for MySQL query?

以下是我正在運行的兩個查詢。 一種需要 75-80 秒,另一種需要 1.0-1.5 秒。 這兩個結果都顯示了預期的 50 行channel_administrators.channel_partner_id 更快和更慢查詢之間的區別在於SELECT從登錄表中選擇唯一登錄。 登錄表有 460833 行,我知道這會減慢查詢速度。 我覺得這是意外的原因是單獨運行這段代碼時,上一個channel_administrators.channel_partner_id結果回來在約0.2至0.7秒,最大channel_administrators.channel_partner_id和50個結果,我不會期望它會超過50-秒。

我希望時間增加在最壞的情況下是線性的,但時間增加似乎不止於此。 這種非線性增加讓我覺得我做錯了什么(非常?),但我不知道如何找出我的查詢出了什么問題。 誰能告訴我為什么在這個查詢中有非線性時間增加?

我在帖子底部包含了一些我運行過的測試查詢及其最新時間。

編輯:我認為這種現象的最佳示例是查看測試 2 和測試 3。這些示例被盡可能地精簡,它顯示了運行邏輯一旦運行很快,但 50 次運行非常緩慢。

編輯 2:我添加了更多數據,在 6.93 秒而不是 75+ 秒內獲得相同的結果。 對於我的系統,我認為這是一個可以接受的結果。 我現在將寫下這個問題的答案。

80 秒查詢:

SELECT 
    info.managed_id,
    info.channel_name,
    info.registered_users, 
    info.new_users, 
    info.active_users, 
    info.coupon_opens
    
FROM channel_administrators

LEFT JOIN (    
    SELECT 
        channel_partners.id AS managed_id,
        channel_partners.name as channel_name,
        (
            SELECT COUNT(users.id) 
            FROM users
            WHERE users.channel_partner_id = channel_partners.id
        ) AS registered_users,
        (
            SELECT COUNT(DISTINCT users.id)
            FROM users
            WHERE users.channel_partner_id = channel_partners.id
            AND users.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
        ) AS new_users,
        (
            SELECT COUNT(DISTINCT logins.user_id)
            FROM logins
            WHERE logins.channel_partner_id = channel_partners.id
            AND logins.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
        ) AS active_users,
        (
            SELECT COUNT(coupon_trackings.id) AS coupon_view_count
            FROM coupon_trackings
            WHERE coupon_trackings.channel_partner_id = channel_partners.id
            AND coupon_trackings.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
        ) AS coupon_opens

    FROM channel_partners
) AS info
ON managed_id = channel_administrators.channel_partner_id

WHERE channel_administrators.user_id = 54184

ORDER BY info.channel_name

1.5 秒查詢(注釋掉差異):

SELECT 
    info.managed_id,
    info.channel_name,
    info.registered_users, 
    info.new_users, 
--     info.active_users, 
    info.coupon_opens
    
FROM channel_administrators

LEFT JOIN (    
    SELECT 
        channel_partners.id AS managed_id,
        channel_partners.name as channel_name,
        (
            SELECT COUNT(users.id) 
            FROM users
            WHERE users.channel_partner_id = channel_partners.id
        ) AS registered_users,
        (
            SELECT COUNT(DISTINCT users.id)
            FROM users
            WHERE users.channel_partner_id = channel_partners.id
            AND users.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
        ) AS new_users,
--         (
--             SELECT COUNT(DISTINCT logins.user_id)
--             FROM logins
--             WHERE logins.channel_partner_id = channel_partners.id
--             AND logins.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
--         ) AS active_users,
        (
            SELECT COUNT(coupon_trackings.id) AS coupon_view_count
            FROM coupon_trackings
            WHERE coupon_trackings.channel_partner_id = channel_partners.id
            AND coupon_trackings.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
        ) AS coupon_opens

    FROM channel_partners
) AS info
ON managed_id = channel_administrators.channel_partner_id

WHERE channel_administrators.user_id = 54184

ORDER BY info.channel_name

下面是我用來測試具有最大結果的通道上的單個時間的查詢。

測試 1:0.441s - 對於單個最大通道:

SELECT 
    channel_partners.id AS managed_id,
    channel_partners.name as channel_name,
    (
        SELECT COUNT(users.id) 
        FROM users
        WHERE users.channel_partner_id = channel_partners.id
    ) AS registered_users,
    (
        SELECT COUNT(DISTINCT users.id)
        FROM users
        WHERE users.channel_partner_id = channel_partners.id
        AND users.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS new_users,
    (
        SELECT COUNT(DISTINCT logins.user_id)
        FROM logins
        WHERE logins.channel_partner_id = channel_partners.id
        AND logins.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS active_users,
    (
        SELECT COUNT(coupon_trackings.id) AS coupon_view_count
        FROM coupon_trackings
        WHERE coupon_trackings.channel_partner_id = channel_partners.id
        AND coupon_trackings.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS coupon_opens

FROM channel_partners

WHERE channel_partners.id = 3255770

測試 2:0.368s - 最大頻道的活躍用戶:

SELECT COUNT(DISTINCT logins.user_id)
FROM logins
WHERE logins.channel_partner_id = 3255770
AND logins.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days

測試3:75.2s 只是登錄信息

SELECT 
    info.managed_id,
    info.channel_name,
    info.active_users    
FROM channel_administrators

LEFT JOIN (    
    SELECT 
        channel_partners.id AS managed_id,
        channel_partners.name as channel_name,
        (
            SELECT COUNT(DISTINCT logins.user_id)
            FROM logins
            WHERE logins.channel_partner_id = channel_partners.id
            AND logins.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
        ) AS active_users

    FROM channel_partners
) AS info
ON info.managed_id = channel_administrators.channel_partner_id

WHERE channel_administrators.user_id = 54184

測試 4:6.93 秒 - 通過重寫取得進展

SELECT 
    channel_partners.id AS managed_id,
    channel_partners.name as channel_name,
    (
        SELECT COUNT(users.id) 
        FROM users
        WHERE users.channel_partner_id = channel_partners.id
    ) AS registered_users,
    (
        SELECT COUNT(DISTINCT users.id)
        FROM users
        WHERE users.channel_partner_id = channel_partners.id
        AND users.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS new_users,
    (
        SELECT COUNT(DISTINCT logins.user_id)
        FROM logins
        WHERE logins.channel_partner_id = channel_partners.id
        AND logins.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS active_users,
    (
        SELECT COUNT(coupon_trackings.id) AS coupon_view_count
        FROM coupon_trackings
        WHERE coupon_trackings.channel_partner_id = channel_partners.id
        AND coupon_trackings.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS coupon_opens

FROM channel_partners

WHERE (channel_partners.id IN (SELECT 
        channel_administrators.channel_partner_id
    FROM channel_administrators
    WHERE channel_administrators.user_id = 54184
    )
) 

編輯:添加查詢結果(刪除名稱)

80年代查詢:

|managed_id|registered_users|new_users|active_users|coupon_opens|
|----------|----------------|---------|------------|------------|
|14        |1146            |46       |282         |893         |
|27        |2159            |48       |206         |635         |
|15        |2039            |68       |490         |2560        |
|16        |15              |0        |1           |0           |
|20        |1391            |53       |413         |1614        |
|21        |3               |0        |0           |0           |
|43        |1051            |36       |255         |1234        |
|44        |706             |19       |85          |276         |
|46        |16              |0        |4           |8           |
|47        |68              |1        |5           |30          |
|48        |169             |6        |40          |308         |
|49        |408             |13       |118         |434         |
|52        |52              |1        |11          |54          |
|53        |378             |11       |111         |391         |
|54        |34              |1        |5           |57          |
|75        |576             |7        |59          |145         |
|3255347   |773             |12       |99          |167         |
|685131    |142             |0        |9           |91          |
|76        |22              |0        |9           |25          |
|55        |276             |5        |68          |251         |
|56        |2232            |79       |534         |1644        |
|57        |78              |0        |10          |47          |
|58        |708             |10       |109         |364         |
|59        |1274            |42       |465         |1929        |
|60        |133             |0        |37          |97          |
|3         |0               |0        |127         |257         |
|2144749   |0               |0        |4           |40          |
|61        |629             |9        |119         |363         |
|63        |857             |36       |267         |892         |
|64        |49              |1        |13          |21          |
|65        |723             |15       |281         |1152        |
|66        |77              |0        |17          |48          |
|67        |123             |10       |59          |190         |
|68        |693             |8        |191         |387         |
|70        |80              |0        |31          |58          |
|71        |214             |1        |41          |102         |
|72        |104             |2        |23          |49          |
|3255770   |3149            |86       |542         |2280        |
|3255771   |3012            |39       |526         |2056        |
|77        |180             |9        |89          |239         |
|477       |677             |5        |286         |583         |
|478       |335             |191      |235         |2226        |
|479       |162             |12       |51          |159         |
|480       |57              |0        |8           |12          |
|302       |51              |3        |17          |32          |
|303       |213             |37       |116         |598         |
|373109    |9               |3        |6           |4           |
|373110    |10              |2        |5           |0           |
|373111    |29              |9        |16          |29          |
|3255810   |0               |0        |0           |0           |

2s查詢:

|managed_id|registered_users|new_users|coupon_opens|
|----------|----------------|---------|------------|
|14        |1146            |46       |893         |
|27        |2159            |48       |635         |
|15        |2039            |68       |2560        |
|16        |15              |0        |0           |
|20        |1391            |53       |1614        |
|21        |3               |0        |0           |
|43        |1051            |36       |1234        |
|44        |706             |19       |276         |
|46        |16              |0        |8           |
|47        |68              |1        |30          |
|48        |169             |6        |308         |
|49        |408             |13       |434         |
|52        |52              |1        |54          |
|53        |378             |11       |391         |
|54        |34              |1        |57          |
|75        |576             |7        |145         |
|3255347   |773             |12       |167         |
|685131    |142             |0        |91          |
|76        |22              |0        |25          |
|55        |276             |5        |251         |
|56        |2232            |79       |1644        |
|57        |78              |0        |47          |
|58        |708             |10       |364         |
|59        |1274            |42       |1929        |
|60        |133             |0        |97          |
|3         |0               |0        |257         |
|2144749   |0               |0        |40          |
|61        |629             |9        |363         |
|63        |857             |36       |892         |
|64        |49              |1        |21          |
|65        |723             |15       |1152        |
|66        |77              |0        |48          |
|67        |123             |10       |190         |
|68        |693             |8        |387         |
|70        |80              |0        |58          |
|71        |214             |1        |102         |
|72        |104             |2        |49          |
|3255770   |3149            |86       |2280        |
|3255771   |3012            |39       |2056        |
|77        |180             |9        |239         |
|477       |677             |5        |583         |
|478       |335             |191      |2226        |
|479       |162             |12       |159         |
|480       |57              |0        |12          |
|302       |51              |3        |32          |
|303       |213             |37       |598         |
|373109    |9               |3        |4           |
|373110    |10              |2        |0           |
|373111    |29              |9        |29          |
|3255810   |0               |0        |0           |

每個表都需要此復合索引,其中的列按給定順序排列:

INDEX(channel_partner_id, created_at)

如果您有這樣的索引,則僅在channel_partner_id上刪除相應的索引。

將此“覆蓋”索引添加到channel_administrators

INDEX(user_id, channel_partner_id)

並刪除INDEX(user_id)如果它存在。

通過不嵌套選擇來簡化查詢:

    SELECT  cp.id AS managed_id,
            cp.name as channel_name,
            (   SELECT  COUNT(users.id)
                    FROM  users
                    WHERE  users.channel_partner_id = cp.id 
            ) AS registered_users,
            ((etc))
        FROM  channel_partners AS cp
        JOIN  channel_administrators AS ca
                ON cp.managed_id = ca.channel_partner_id
        WHERE  ca.user_id = 54184
        ORDER  BY  channel_name 

提示:考慮改變

created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days

    created_at >= '2021-06-03'
AND created_at  < '2021-06-03' + INTERVAL 30 DAY

或者如果更合適,使用+ INTERVAL 1 MONTH

如果您仍然有性能問題,讓我們看看查詢的樣子提供SHOW CREATE TABLE

我仍然不知道為什么這會運行緩慢,但我找到了一個提高速度的解決方案,並將顯示我如何到達那里的步驟。

首先,在原始問題的測試 2 2 和測試 3 中,您可以看到對登錄表的單個查詢非常快,但是當查詢多個channel_partner_id ,整個查詢變得非常慢。 我懷疑這與我如何根據登錄表檢查channel_partner_id有關。

我重寫了查詢以從列表而不是從選擇中獲取channel_partner_id 最終結果如下所示:

SELECT 
    channel_partners.id AS managed_id,
    channel_partners.name as channel_name,
    (
        SELECT COUNT(users.id) 
        FROM users
        WHERE users.channel_partner_id = channel_partners.id
    ) AS registered_users,
    (
        SELECT COUNT(DISTINCT users.id)
        FROM users
        WHERE users.channel_partner_id = channel_partners.id
        AND users.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS new_users,
    (
        SELECT COUNT(DISTINCT logins.user_id)
        FROM logins
        WHERE logins.channel_partner_id = channel_partners.id
        AND logins.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS active_users,
    (
        SELECT COUNT(coupon_trackings.id) AS coupon_view_count
        FROM coupon_trackings
        WHERE coupon_trackings.channel_partner_id = channel_partners.id
        AND coupon_trackings.created_at BETWEEN '2021-06-03' AND '2021-07-03' -- 30 days
    ) AS coupon_opens

FROM channel_partners

WHERE (channel_partners.id IN (SELECT 
        channel_administrators.channel_partner_id
    FROM channel_administrators
    WHERE channel_administrators.user_id = 54184
    )
) 

這個查詢花費了 6.93 秒,這仍然很慢,但它更接近我預期查詢所需的時間。

我無法解釋為什么一種方式更快,一種方式更慢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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