1

在我的查询从几秒钟跳到几小时之前,我一直在体验出色的性能。

A) 调查 B) 在 Mysql 上查询过多数据时解决主要的性能瓶颈,我该怎么做?

也许与记忆有关?


结果

在测试存储过程的性能时,我在 5 分钟内运行了两次,首先...

mysql> CALL TopFromBigTable('2012-04-01','2012-05-01',5);
5 rows in set (23.76 sec)

这是非常快的,但后来我再次调用它......我在一个多小时后杀死了它!

mysql> CALL TopFromBigTable('2012-04-01','2012-05-01',5);

---TRANSACTION 1484EF5C, ACTIVE 3571 sec fetching rows, thread declared inside InnoDB 193
mysql tables in use 2, locked 1
MySQL thread id 466174, OS thread handle 0x7f3616ab4700, query id 33098684 localhost    root Copying to tmp table

更多测试:

mysql> CALL TopFromBigTable('2012-05-01','2012-05-04',5);
5 rows in set (1.28 sec)
mysql> CALL TopFromBigTable('2012-05-01','2012-05-05',5);
5 rows in set (1.55 sec)
mysql> CALL TopFromBigTable('2012-05-01','2012-05-06',5);
5 rows in set (1 hour 47 min 37.99 sec)

细节

桌子

CREATE TABLE `BigTable` (
  `BigTableID` int(11) NOT NULL,
  `AnotherID` int(11) NOT NULL,
  `Type` char(2) COLLATE utf8_unicode_ci DEFAULT NULL,
  `StartTime` datetime NOT NULL,
  `EndTime` datetime DEFAULT NULL,
  PRIMARY KEY (`BigTableID`),
  KEY `Type` (`Type`),
  KEY `StartTime` (`StartTime`),
  KEY `EndTime` (`EndTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

查询(注意使这个通用我group by错了

CREATE PROCEDURE `TopFromBigTable` (
    $StartDate DATETIME,
    $EndDate DATETIME,
    $ResultLimit INT
    )
BEGIN

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ;
    SELECT
        `Type`,
        COUNT(*) AS Count
    FROM
        `BigTable`
    WHERE                
            `StartTime` > $StartDate
        AND
            `StartTime` < $EndDate
    GROUP BY
        `Type`
    ORDER BY
        Count DESC
    LIMIT $ResultLimit
    ;
    COMMIT;

END $$

执行计划

EXPLAIN EXTENDED ...
           id: 1
  select_type: SIMPLE
        table: BigTable
         type: range
possible_keys: StartTime
          key: StartTime
      key_len: 8
          ref: NULL
         rows: 16446226
     filtered: 100.00
        Extra: Using where; Using temporary; Using filesort

我在专用报告数据库上运行,因此并非所有正常规则都适用,即我阅读未提交以试图降低开销,因为准确性并不重要,并且该数据库在过去 6 小时内未更新。我想对这实际上有多大帮助(如果有的话)进行基准测试,但我无法可靠地为存储过程计时!

4

3 回答 3

1

这是一个艰难的...如果它真的是一个大表 - 在 StartTime 中添加和索引可能需要一些时间和一些额外的空间,但会提高选择速度,前提是根据http://dev指定 USE INDEX .mysql.com/doc/refman/5.1/en/index-hints.html

请务必根据每天插入的行数重新索引...请自行决定。

在研究您的有趣问题时,我也遇到了这个问题:http ://www.petefreitag.com/item/613.cfm

于 2012-05-28T22:13:00.430 回答
0

详细解答。

  1. 将您的存储过程分解为示例查询
  2. 采用EXPLAIN EXTENDED
  3. 使用EXPLAIN EXTENDED不同的输入,因为优化器可以改变计划!

随机行为是优化器以不同的方式计算表统计信息(随着时间的推移它在后台这样做)并选择了一个不太有效的索引。解决方案是通过提示强制使用更好USE INDEX(StartTime)的索引或调整索引。

好的

EXPLAIN EXTENDED
SELECT
    `Type`,
    COUNT(*) AS Count
FROM
    `BigTable`
WHERE                
        (`StartTime` > '2012-02-01')  
    AND
        (`StartTime` < '2012-02-02' ) 
GROUP BY
    `Type`
ORDER BY
    Count DESC
LIMIT 5
;

           id: 1
  select_type: SIMPLE
        table: BigTable
         type: range
possible_keys: StartTime
          key: StartTime
      key_len: 8
          ref: NULL
         rows: 170986
     filtered: 100.00
        Extra: Using where; Using temporary; Using filesort

坏(错误的索引,38M 行和 15% 已过滤)

EXPLAIN EXTENDED
SELECT
    `Type`,
    COUNT(*) AS Count
FROM
    `BigTable`
WHERE                
        (`StartTime` > '2012-02-01')  
    AND
        (`StartTime` < '2012-03-01' ) 
GROUP BY
    `Type`
ORDER BY
    Count DESC
LIMIT 5
;
           id: 1
  select_type: SIMPLE
        table: BigTable
         type: index
possible_keys: StartTime
          key: Type
      key_len: 7
          ref: NULL
         rows: 38311434
     filtered: 14.54
        Extra: Using where; Using temporary; Using filesort

固定(5M 行)

EXPLAIN EXTENDED
SELECT
    `Type`,
    COUNT(*) AS Count
FROM
    `BigTable`
    USE INDEX (`StartTime`)
WHERE                
        (`StartTime` > '2012-02-01')  
    AND
        (`StartTime` < '2012-02-02' ) 
GROUP BY
    `Type`
ORDER BY
    Count DESC
LIMIT 5
;

           id: 1
  select_type: SIMPLE
        table: BigTable
         type: range
possible_keys: StartTime
          key: StartTime
      key_len: 8
          ref: NULL
         rows: 5572320
     filtered: 100.00
        Extra: Using where; Using temporary; Using filesort
于 2012-05-30T22:20:13.540 回答
0

由于您按Type它分组只有几个 (50) 不同的值,而不是 100K 值,我看到 2 个选项:

  • 复合(Type, StartTime)索引。

索引“覆盖”了查询,这意味着查询将只使用索引而不命中表。它仍然需要扫描大部分索引并计算每个项目的数量Type,所以它不是最好的希望,但Type表中只有 50 个值,我认为它会表现良好。(最终的文件排序 - 只有 50 行 - 不会有问题。)

  • 此查询的另一个覆盖索引是 Compound (StartTime, Type)

如果查询使用这个,它将从索引的一部分读取所有数据,因此在某些情况下它可能会更快(当开始-结束时间窗口很小并且Type有更多不同的值时)。但是 group byType可能会使这个性能不如第一个,尤其是在大窗户的情况下。

我认为最好的方法是同时使用上述指标和各种参数进行测试/实验。

于 2012-05-30T22:26:46.123 回答