针对大量数据的高效MySQL查询

时间:2017-09-15 21:58:25

标签: mysql query-optimization

说我有一张如下表:

CREATE TABLE `hadoop_apps` (
  `clusterId` smallint(5) unsigned NOT NULL,
  `appId` varchar(35) COLLATE utf8_unicode_ci NOT NULL,
  `user` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
  `queue` varchar(35) COLLATE utf8_unicode_ci NOT NULL,
  `appName` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  `submitTime` datetime NOT NULL COMMENT 'App submission time',
  `finishTime` datetime DEFAULT NULL COMMENT 'App completion time',
  `elapsedTime` int(11) DEFAULT NULL COMMENT 'App duration in milliseconds',
  PRIMARY KEY (`clusterId`,`appId`,`submitTime`),
  KEY `hadoop_apps_ibk_finish` (`finishTime`),
  KEY `hadoop_apps_ibk_queueCluster` (`queue`,`clusterId`),
  KEY `hadoop_apps_ibk_userCluster` (`user`(8),`clusterId`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

mysql> SELECT COUNT(*) FROM hadoop_apps;

这会给我一个计数158593816

所以我试图了解以下查询的低效率以及如何改进它。

mysql> SELECT * FROM hadoop_apps WHERE DATE(finishTime)='10-11-2013';

另外,这两个查询之间的区别是什么?

mysql> SELECT * FROM hadoop_apps WHERE user='foobar';
mysql> SELECT * FROM hadoop_apps HAVING user='foobar';

2 个答案:

答案 0 :(得分:3)

  

WHATE DATE(finishTime)='10-11-2013';

这是优化器的问题,因为无论何时将列放入这样的函数中,优化器都不知道函数返回的值的顺序是否与输入到函数的值的顺序相同。所以它不能使用索引来加速查找。

要解决这个问题,如果希望对该列的查找使用索引,请不要将列放在函数调用中。

此外,您应该使用MySQL标准日期格式:YYYY-MM-DD。

WHERE finishTime BETWEEN '2013-10-11 00:00:00' AND '2013-10-11 23:59:59'
  

[WHERE和HAVING条款中的条件]有什么区别?

WHERE子句用于过滤行。

HAVING子句用于在应用GROUP BY后过滤结果

请参阅SQL - having VS where

答案 1 :(得分:1)

如果WHERE有效,则优先于HAVING。前者在处理的早期完成,从而减少了要挖掘的数据量。好的,在你的一个例子中,它们之间可能没有区别。

每当我在DATETIME键(你的PK)中看到UNIQUE时,我都会畏缩不前。该应用无法在同一秒内拥有两行吗?这是你想要冒的风险。

即使更改为DATETIME(6)(微秒)也可能存在风险。

无论您在该领域做了什么,我都建议使用此模式进行测试:

WHERE finishTime >= '2013-10-11'
  AND finishTime  < '2013-10-11' + INTERVAL 1 DAY

它正常工作&#34;正确&#34;适用于DATEDATETIMEDATETIME(6)等。其他口味会增加额外的午夜或错过部分时间。如果间隔时间超过一天,它就可以避免与leapdays等相关的麻烦。

KEY `hadoop_apps_ibk_userCluster` (`user`(8),`clusterId`)

很糟糕。它不会超过user(8)。像这样的前缀通常是无用的。让我们看看诱惑你构建该密钥的查询;我们会想出一个更好的。

158M行,包含4个varchars。他们听起来像没有许多不同价值观的价值观?构建查找表并将其替换为SMALLINT UNSIGNED(2个字节,0..64K范围)或其他小ID。这将显着缩小表格,从而使其更快。