【问题标题】:MySQL user blocking query slow - social network designMySQL 用户阻塞查询慢 - 社交网络设计
【发布时间】:2019-12-20 15:13:38
【问题描述】:

我正在开发一个小型社交网络,但我正在努力优化设计中的屏蔽部分。我有 3 个表阻塞、提要和用户。它工作正常,但是当我添加阻止查询时,查询从 16 毫秒或更少到超过 50 毫秒或更高,这对于简单的事情来说似乎很多。事实上,如果没有阻塞我的 hedisql sql,查询时间有时会报告为 0ms,因为我猜它低于一定的时间。

屏蔽的想法是,如果用户屏蔽了其他人,他们将无法看到他们的提要帖子,被屏蔽的人也无法看到屏蔽者。

我正在努力优化的部分是: LEFT JOIN 阻塞 ON blocking.blockerId = feed.userId AND blocking.blockedId = '3' OR blocking.blockerId = '3' AND blocking.blockedId = feed.userId 其中blocking.blockerId 为NULL 且blocking.blockedId 为NULL

有没有一种方法可以在不更改数据的情况下改进此查询,或者是否可以达到预期效果?

我正在尝试优化的查询:

SELECT users.displayName, feed.id, feed.userId, feed.message
FROM feed
INNER JOIN users ON feed.userId = users.id
LEFT JOIN blocking ON blocking.blockerId = feed.userId AND blocking.blockedId = '3' OR blocking.blockerId = '3' AND blocking.blockedId = feed.userId
WHERE blocking.blockerId IS NULL AND blocking.blockedId IS NULL
ORDER BY feed.id DESC
LIMIT 20;

阻塞表和键:

CREATE TABLE IF NOT EXISTS `blocking` (
  `blockerId` int(11) NOT NULL,
  `blockedId` int(11) NOT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`blockedId`,`blockerId`) USING BTREE,
  KEY `userId` (`blockerId`,`blockedId`) USING BTREE,
  CONSTRAINT `blockedId` FOREIGN KEY (`blockedId`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `blockerId` FOREIGN KEY (`blockerId`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
)

饲料表:

CREATE TABLE IF NOT EXISTS `feed` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `userId` int(11) NOT NULL,
  `message` varchar(300) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `userId` (`userId`),
  KEY `timestamp` (`timestamp`),
  CONSTRAINT `userIdCas` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
)

用户表:

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
  `displayName` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL,
  `password` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `createdAt` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`),
) 

解释不阻塞:

用阻塞来解释:


我正在调整的更新查询似乎运行得更快:

FROM feed
FORCE INDEX (PRIMARY)
INNER JOIN users ON feed.userId = users.id
LEFT JOIN blocking ON blocking.blockerId = feed.userId AND blocking.blockedId = '3' OR blocking.blockerId = '3' AND blocking.blockedId = feed.userId
WHERE blocking.blockerId IS NULL AND blocking.blockedId IS NULL
ORDER BY feed.id DESC
LIMIT 20;

谁能解释为什么它运行得更好以及为什么 MySQL 可能不使用索引开始?

(来自评论)我将查询更改为

SELECT  users.displayName, feed.id, feed.userId, feed.message
    FROM  feed FORCE INDEX (PRIMARY)
    INNER JOIN  users  ON feed.userId = users.id
    LEFT JOIN  blocking  ON blocking.blockerId = feed.userId
      AND  blocking.blockedId = '3'
      OR  blocking.blockerId = '3'
      AND  blocking.blockedId = feed.userId
    WHERE  blocking.blockerId IS NULL
      AND  blocking.blockedId IS NULL
    ORDER BY  feed.id DESC
    LIMIT  20;

而且它似乎运行得更好,谁能让我更深入地理解为什么?

【问题讨论】:

  • 我也更改了查询:SELECT users.displayName, feed.id, feed.userId, feed.message FROM feed FORCE INDEX (PRIMARY) INNER JOIN users ON feed.userId = users.id LEFT JOIN阻塞 ON blocking.blockerId = feed.userId AND blocking.blockedId = '3' OR blocking.blockerId = '3' AND blocking.blockedId = feed.userId WHERE blocking.blockerId 为 NULL AND blocking.blockedId 为 NULL ORDER BY feed.id DESC 限制 20; ```而且它似乎运行得更好,谁能给我更深入的理解为什么?
  • 请考虑更改名称 blockerId 和/或blockedId - 它们的相似性使得阅读查询变得非常困难。
  • 不使用FORCE INDEXEXPLAIN会说什么?

标签: mysql performance query-optimization


【解决方案1】:

你应该在 OR 条件周围使用 () 否则你会得到 udesidered 的结果

SELECT users.displayName
  , feed.id
  , feed.userId
  , feed.message
FROM feed
INNER JOIN users ON feed.userId = users.id
LEFT JOIN blocking ON blocking.blockerId = feed.userId 
  AND ( blocking.blockedId = '3' OR blocking.blockerId = '3' )
  AND blocking.blockedId = feed.userId
WHERE blocking.blockerId IS NULL AND blocking.blockedId IS NULL
ORDER BY feed.id DESC
LIMIT 20;

为了获得更好的性能,您可以尝试在表上添加复合索引

table  blocking columns  ( blockerId, blockedId   )

也是表上的复合索引

table  feed columns  (userId,  message, id )  

【讨论】:

  • (看起来像索引中的 dup 列)
猜你喜欢
  • 2016-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-08
相关资源
最近更新 更多