【问题标题】:SQL query uses a lot of CPU and takes too long timeSQL查询占用大量CPU,耗时过长
【发布时间】:2021-07-07 17:26:42
【问题描述】:

我有一个应用程序,您可以在其中滑动到 Tinder 等匹配项。在滑动页面上,您应该可以看到所有您之前没有滑动过的用户。

我有这 4 张桌子。 UsersMatchesSwipedNoSwipedYes。检查用户是否在swipedNoswipedYesmatches下。如果用户不在这些表之一中,则必须显示该用户。

用户:

CREATE TABLE `users` (
  `id` bigint(20) NOT NULL,
  `landcode` bigint(20) NOT NULL,
  `phone` int(10) NOT NULL,
  `code` int(10) NOT NULL,
  `codeExpires` datetime NOT NULL,
  `name` varchar(25) COLLATE utf8mb4_bin DEFAULT NULL,
  `gender` int(2) DEFAULT NULL,
  `birth` date DEFAULT NULL,
  `latitude` double NOT NULL DEFAULT 0,
  `longitude` double NOT NULL DEFAULT 0,
  `bio` text COLLATE utf8mb4_bin DEFAULT NULL,
  `lastActive` datetime NOT NULL DEFAULT current_timestamp(),
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

SwipedNo/SwipedYes:

CREATE TABLE `swipedNo` (
  `id` bigint(20) NOT NULL,
  `user1` bigint(20) NOT NULL,
  `user2` bigint(20) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user1` (`user1`,`user2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

匹配:

CREATE TABLE `matches` (
  `id` bigint(20) NOT NULL,
  `user1` bigint(20) NOT NULL,
  `user2` bigint(20) NOT NULL,
  `dato` datetime NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user1` (`user1`,`user2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

我做了这个 SQL 查询,但它使用大量 CPU,平均需要 10 秒。

SELECT id, name, birth, gender, newUser, distance FROM 

    (SELECT 
    u.id,
    u.name,
    u.birth,
    u.gender,
    u.newUser,
    (
        6371 *
       acos(cos(radians(55.6)) * 
       cos(radians(u.latitude)) * 
       cos(radians(u.longitude) - 
       radians(12.5)) + 
       sin(radians(55.6)) * 
       sin(radians(u.latitude )))
    ) AS distance
    FROM users u
    
    LEFT JOIN
    
    (SELECT 
    swipes.user1,
    swipes.user2

    FROM users u
    
    LEFT JOIN
    (SELECT user1, user2 FROM swipedNo
    UNION
    SELECT user1, user2 FROM swipedYes
    UNION
    SELECT user1, user2 FROM matches
    UNION
    SELECT user2, user1 FROM matches)

    as swipes ON swipes.user2 = u.id
    
    WHERE   
    swipes.user1=71211776843542) as outerSwipes ON outerSwipes.user2 = u.id
    
    WHERE
    outerSwipes.user2 IS NULL) as outerUsers
    WHERE
    outerUsers.distance <= 150
    LIMIT 200

对给定查询的解释:

我希望您有一些建议可以帮助减少 CPU 消耗和执行时间。

【问题讨论】:

  • 建议的查询有帮助吗?您能否在提供的答案中分享Explain 的查询?

标签: mysql sql performance database-design


【解决方案1】:

从性能角度和问题中提供的详细信息来看,很难复制您的环境或场景。需要提供基准数据集和系统要求。

但是,如果您想要关于查询设计的替代建议。然后,您可以分享以下查询的性能指标:

-- the user that new interactions are sought for
-- user id to ignore : 71211776843542
SELECT *
FROM   (SELECT u.id,
               u.name,
               u.birth,
               u.gender,
               -- this column does not exist in the schema shared
               -- 
               -- u.newUser, 
               ( 6371 * ACOS(COS(RADIANS(55.6)) * COS(RADIANS(u.latitude)) * COS
                             (
                                           RADIANS(u.longitude) - RADIANS(12.5))
                             +
                                      SIN(RADIANS(55.6)) * SIN(
                                      RADIANS(u.latitude))) )
                      AS
               distance
        FROM   users u
        WHERE  NOT EXISTS (SELECT id
                           FROM   swipedno
                           WHERE  ( user1 = 71211776843542
                                    AND user2 = u.id )
                               OR ( user2 = 71211776843542
                                    AND user1 = u.id )
                           UNION ALL
                           SELECT id
                           FROM   swipedyes
                           WHERE  ( user1 = 71211776843542
                                    AND user2 = u.id )
                               OR ( user2 = 71211776843542
                                    AND user1 = u.id )
                           UNION ALL
                           SELECT id
                           FROM   matches
                           WHERE  ( user1 = 71211776843542
                                    AND user2 = u.id )
                               OR ( user2 = 71211776843542
                                    AND user1 = u.id ))) t
WHERE  t.distance < 150
LIMIT  200 

【讨论】:

    猜你喜欢
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    相关资源
    最近更新 更多