MySQL用户阻止查询缓慢-社交网络设计

时间:2019-12-08 16:56:40

标签: mysql performance query-optimization

我正在一个小型社交网络上工作,但是我正在努力优化设计的阻碍部分。我有3个表阻止,供稿和用户。它工作正常,但是当我添加阻止查询时,查询时间从16ms或更短到超过50ms或更高,对于简单的事情来说似乎很多。实际上,在我的hedisql sql中没有阻塞的情况下,有时查询时间报告为0ms,因为我猜它低于一定的时间。

屏蔽的想法是,如果用户屏蔽了其他人,则他们将无法看到自己的供稿,而被屏蔽的人将无法看到屏蔽器。

我正在努力优化的部分是: 左联接阻塞ON阻塞.blockerId = feed.userId AND阻塞.blockedId ='3'或阻塞.blockerId ='3'AND阻塞.blockedId = feed.userId WHERE 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`),
) 

请说明而不阻塞: enter image description here

解释阻止: enter image description here


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

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;

运行起来似乎更好,谁能让我对原因有更深入的了解?

1 个答案:

答案 0 :(得分:1)

您应该在OR条件附近使用(),否则您将获得令人讨厌的结果

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 )