查询优化以查找随机样本

时间:2013-11-19 14:11:15

标签: mysql sql random-sample

我有一个sql查询来随机选择1200个转发的转发推文,至少转发50次,而tweetDate应该比4千万条记录早4天。我下面粘贴的查询有效,但需要40分钟,那么该查询的版本是否更快?

SELECT 
    originalTweetId, Count(*) as total, tweetContent, tweetDate
FROM
    twitter_gokhan2.tweetentities
WHERE
    originalTweetId IS NOT NULL
        AND originalTweetId <> - 1
        AND isRetweet = true
    AND (tweetDate < DATE_ADD(CURDATE(), INTERVAL - 4 DAY))
GROUP BY originalTweetId
HAVING total > 50
ORDER BY RAND()
limit 0 , 1200;


---------------------------------------------------------------

Table creation sql is like:

    CREATE TABLE `tweetentities` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `tweetId` bigint(20) NOT NULL,
      `tweetContent` varchar(360) DEFAULT NULL,
      `tweetDate` datetime DEFAULT NULL,
      `userId` bigint(20) DEFAULT NULL,
      `userName` varchar(100) DEFAULT NULL,
      `retweetCount` int(11) DEFAULT '0',
      `keyword` varchar(500) DEFAULT NULL,
      `isRetweet` bit(1) DEFAULT b'0',
      `isCompleted` bit(1) DEFAULT b'0',
      `applicationId` int(11) DEFAULT NULL,
      `latitudeData` double DEFAULT NULL,
      `longitude` double DEFAULT NULL,
      `originalTweetId` bigint(20) DEFAULT NULL,
     PRIMARY KEY (`id`),
  KEY `index` (`originalTweetId`),
  KEY `index3` (`applicationId`),
  KEY `index2` (`tweetId`),
  KEY `index4` (`userId`),
  KEY `index5` (`userName`),
  KEY `index6` (`isRetweet`),
  KEY `index7` (`tweetDate`),
  KEY `index8` (`originalTweetId`),
  KEY `index9` (`isCompleted`),
  KEY `index10` (`tweetContent`(191))
) ENGINE=InnoDB AUTO_INCREMENT=41501628 DEFAULT CHARSET=utf8mb4$$

4 个答案:

答案 0 :(得分:1)

当然,您总结了巨大的个记录,然后将它们随机化。这种事情很难快速发展。回到开始的时候会让事情变得更糟。在空条件下搜索只会破坏它。

如果您希望合理地执行此操作,则必须摆脱IS NOT NULL选择。否则,它将表现不佳。

但是,让我们试着找到一个合理的解决方案。首先,让我们得到我们需要的originalTweetId值。

 SELECT MIN(id) originalId,
        MIN(tweetDate) tweetDate,
        originalTweetId, 
        Count(*) as total
   FROM twitter_gokhan2.tweetentities
  WHERE originalTweetId <> -1 
  /*AND originalTweetId IS NOT NULL We have to leave this out for perf reasons */
    AND isRetweet = true
    AND tweetDate < CURDATE() - INTERVAL 4 DAY
    AND tweetDate > CURDATE() - INTERVAL 30 DAY  /*let's add this, if we can*/
  GROUP BY originalTweetId
 HAVING total >= 50

此摘要查询为我们提供了每个主题推文的数据库中最低的ID号和日期。

为了让它快速运行,我们需要一个复合索引(originalTweetId,isRetweet,tweetDate,id)。该查询将在tweetDate上对该索引进行范围扫描,其速度与您希望的速度一样快。调试此查询,无论是为了正确性还是性能,然后继续。

现在进行随机化。让我们用尽可能少的数据来做这件事,以避免分类大量的东西。

 SELECT originalTweetId, tweetDate, total, RAND() AS randomOrder
   FROM (
    SELECT MIN(id) originalId,
           MIN(tweetDate) tweetDate
           originalTweetId, 
           Count(*) as total
      FROM twitter_gokhan2.tweetentities
     WHERE originalTweetId <> -1 
     /*AND originalTweetId IS NOT NULL We have to leave this out for perf reasons */
       AND isRetweet = true
       AND tweetDate < CURDATE() - INTERVAL 4 DAY
       AND tweetDate > CURDATE() - INTERVAL 30 DAY  /*let's add this, if we can*/
      GROUP BY originalTweetId
     HAVING total >= 50
   ) AS retweets
  ORDER BY randomOrder
  LIMIT 1200

大。现在我们以随机顺序列出了1200条推文ID和日期。现在我们来看看内容。

 SELECT a.originalTweetId, a.total, b.tweetContent, a.tweetDate
   FROM (
          /* that whole query above */
        ) AS a
   JOIN twitter_gokhan2.tweetentities AS b ON (a.id = b.id)
  ORDER BY a.randomOrder

看看这是怎么回事?使用复合索引来执行摘要,并使用最少量的数据执行此操作。然后进行随机化,然后获取所需的额外数据。

答案 1 :(得分:0)

您通过选择4天以上的每条记录来选择大量记录....

由于查询需要花费大量时间,为什么不使用在后台重复运行的独立脚本来准备结果....

你或许可以假设如果它是转发,那么originalTweetId不能为null / -1

答案 2 :(得分:0)

只是为了澄清......你真的是想要查询所有OLDER而不是4天吗?

 AND (tweetDate < DATE_ADD(CURDATE(), INTERVAL - 4 DAY))

或者......你的意思是你只想在最近4天内汇总最近的TWEETS。对我来说,2年前发生的推文对于当前的事件来说毫无价值......如果是这样的话,你可能会更好地改为

 AND (tweetDate >= DATE_ADD(CURDATE(), INTERVAL - 4 DAY))

答案 3 :(得分:0)

看看这是不是比40分钟快一点:

首先在没有注释行的情况下进行测试,然后重新添加它们以比较性能影响。 (特别是ORDER BY RAND()被认为是可怕的)

SELECT
    originalTweetId,
    total,
--    tweetContent,  -- may slow things somewhat
    tweetDate
FROM (
  SELECT
    originalTweetId,
    COUNT(*) AS total,
--    tweetContent,  -- may slow things somewhat
    MIN(tweetDate) AS tweetDate,
    MAX(isRetweet) AS isRetweet
  FROM twitter_gokhan2.tweetentities
  GROUP BY originalTweetId
) AS t
WHERE originalTweetId > 0
  AND isRetweet
  AND tweetDate < DATE_ADD(CURDATE(), INTERVAL - 4 DAY)
  AND total > 50
-- ORDER BY RAND()  -- very likely to slow performance,
                    -- test with and without...
LIMIT 0, 1200;

PS - originalTweetId应该有希望索引