2016-02-27 34 views
3

我想运行一个简单的SELECT查询与基于PRIMARY KEY的WHERE语句。我在32核心和30 GB RAM的GCE实例上运行MySQL 5.7.9。 500个分区中有〜300M记录。我的查询中有99.9999%来自过去2天,而且这些数据完全符合内存,经过验证,我看到从磁盘读取约0个字节。我的CPU一直在100%挂起,其中10-20个同时运行的类似查询。MySQL的主键查询扫描5000x太多行

我正在跟踪一些Google搜索数据,因此每个组合的Requested,IsPriorityKeywordID有100个rank s。尽管我的主索引被设计为不需要扫描,但当我查看EXPLAIN时,它显示正在扫描552k行以返回100行。

平均而言,从RAM中返回100个直接由主键指向的行需要20-40s。我能做些什么来加速这个查询?

EXPLAIN EXTENDED SELECT * FROM data.Rankings 
    -> WHERE Requested = '2016-02-26 00:00:00' AND NOT IsPriority AND KeywordID = '7387777811691965572'\G 
*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: Rankings 
    partitions: p20160226 
     type: ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: const 
     rows: 552598 
    filtered: 1.00 
     Extra: Using where 
1 row in set, 2 warnings (0.01 sec) 

这里的数据库表

CREATE TABLE `Rankings` (
    `KeywordID` char(20) COLLATE utf8mb4_unicode_ci NOT NULL, 
    `Requested` timestamp NOT NULL, 
    `IsPriority` tinyint(1) NOT NULL, 
    `Retrieved` timestamp NOT NULL, 
    `Rank` tinyint(4) NOT NULL, 
    `Source` varchar(5) COLLATE utf8mb4_unicode_ci NOT NULL, 
    `ExternalID` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL, 
    `Phrase` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, 
    // another 40 data columns of varying types 
    PRIMARY KEY (`Requested`,`IsPriority`,`KeywordID`,`Rank`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED 
// I have about 500 daily partitions over the last 1.5 years 
/*!50100 PARTITION BY RANGE (UNIX_TIMESTAMP(Requested)) 
(PARTITION p20160222 VALUES LESS THAN (1456185600) ENGINE = InnoDB, 
PARTITION p20160223 VALUES LESS THAN (1456272000) ENGINE = InnoDB, 
PARTITION p20160224 VALUES LESS THAN (1456358400) ENGINE = InnoDB, 
PARTITION p20160225 VALUES LESS THAN (1456444800) ENGINE = InnoDB, 
PARTITION p20160226 VALUES LESS THAN (1456531200) ENGINE = InnoDB, 
PARTITION p20160227 VALUES LESS THAN (1456617600) ENGINE = InnoDB, 
PARTITION p20160228 VALUES LESS THAN (1456704000) ENGINE = InnoDB, 
PARTITION p20160229 VALUES LESS THAN (1456790400) ENGINE = InnoDB) */; 
+0

我得仔细看才能提供一个可靠的答案。我通常在索引中避免复合键 - 查询优化器必须做很多工作才能确定它是否可以将PK用作索引。相反,请考虑在每个字段上创建多个索引。 –

回答

5

我怀疑NOT导致的问题。如何使用平等比较?

SELECT * 
FROM data.Rankings 
WHERE Requested = '2016-02-26 00:00:00' AND 
     IsPriority = 0 AND 
     KeywordID = '7387777811691965572'; 
+1

立即解决问题!太疯狂了!我会在SO让我时在3分钟内将其标记为已接受。我非常感谢所有人为什么会在执行时间上产生如此巨大的差异,同时仍然返回相同的结果。 –

+1

@DerekPerkins。 。 。我认为答案是优化器首先必须识别数字类型的“NOT IsPriority”和“IsPriority = 0”的等价性,然后应用此信息。这个构造可能太稀罕了(并且很容易解决),因为这是设计师的想法。 –

+0

我觉得有道理。我一定会对未来更加警惕。 :) –