改善查询速度建议

时间:2019-05-09 15:07:41

标签: mysql performance indexing

对于自我教育,我正在为一家电力公司开发一个发票系统。我有多个时间序列表,间隔时间不同。一个表代表消费,另外两个表代表价格。第三价格表应该仍然合并。现在我正在运行计算查询,但是查询很慢。我想提高查询速度,尤其是因为这只是开始计算,查询只会变得更加复杂。还请注意,这是我创建的第一个数据库,也是我做过的练习。首选简化的解释。感谢您提供的任何帮助。

我已在每个表中建立索引:DATE, PERIOD_FROM, PERIOD_UNTIL。这样可以将过程从60秒加快到5秒。

  

表的结构如下:

CREATE TABLE `apxprice` (
 `APX_id` int(11) NOT NULL AUTO_INCREMENT,
 `DATE` date DEFAULT NULL,
 `PERIOD_FROM` time DEFAULT NULL,
 `PERIOD_UNTIL` time DEFAULT NULL,
 `PRICE` decimal(10,2) DEFAULT NULL,
 PRIMARY KEY (`APX_id`)
) ENGINE=MyISAM AUTO_INCREMENT=28728 DEFAULT CHARSET=latin1

CREATE TABLE `imbalanceprice` (
 `imbalanceprice_id` int(11) NOT NULL AUTO_INCREMENT,
 `DATE` date DEFAULT NULL,
 `PTU` tinyint(3) DEFAULT NULL,
 `PERIOD_FROM` time DEFAULT NULL,
 `PERIOD_UNTIL` time DEFAULT NULL,
 `UPWARD_INCIDENT_RESERVE` tinyint(1) DEFAULT NULL,
 `DOWNWARD_INCIDENT_RESERVE` tinyint(1) DEFAULT NULL,
 `UPWARD_DISPATCH` decimal(10,2) DEFAULT NULL,
 `DOWNWARD_DISPATCH` decimal(10,2) DEFAULT NULL,
 `INCENTIVE_COMPONENT` decimal(10,2) DEFAULT NULL,
 `TAKE_FROM_SYSTEM` decimal(10,2) DEFAULT NULL,
 `FEED_INTO_SYSTEM` decimal(10,2) DEFAULT NULL,
 `REGULATION_STATE` tinyint(1) DEFAULT NULL,
 `HOUR` int(2) DEFAULT NULL,
 PRIMARY KEY (`imbalanceprice_id`),
 KEY `DATE` (`DATE`,`PERIOD_FROM`,`PERIOD_UNTIL`)
) ENGINE=MyISAM AUTO_INCREMENT=117427 DEFAULT CHARSET=latin

CREATE TABLE `powerload` (
 `powerload_id` int(11) NOT NULL AUTO_INCREMENT,
 `EAN` varchar(18) DEFAULT NULL,
 `DATE` date DEFAULT NULL,
 `PERIOD_FROM` time DEFAULT NULL,
 `PERIOD_UNTIL` time DEFAULT NULL,
 `POWERLOAD` int(11) DEFAULT NULL,
 PRIMARY KEY (`powerload_id`)
) ENGINE=MyISAM AUTO_INCREMENT=61039 DEFAULT CHARSET=latin

现在运行此查询时:

SELECT  i.DATE, i.PERIOD_FROM, i.TAKE_FROM_SYSTEM, i.FEED_INTO_SYSTEM,
        a.PRICE, p.POWERLOAD, sum(a.PRICE * p.POWERLOAD)
    FROM  imbalanceprice i, apxprice a, powerload p
    WHERE  i.DATE = a.DATE
      and  i.DATE = p.DATE
      AND  i.PERIOD_FROM >= a.PERIOD_FROM
      and  i.PERIOD_FROM = p.PERIOD_FROM
      AND  i.PERIOD_FROM < a.PERIOD_UNTIL
      AND  i.DATE >= '2018-01-01'
      AND  i.DATE <= '2018-01-31'
    group by  i.DATE

我已经运行了带有explain的查询,并得到以下结果:Select_type,所有简单分区全部为null可能的键a,p = null i = DATE键a,p = null i = DATE key_len a,p = null i = 8 ref a,p = null i = timeseries.a.DATE,timeseries.p.PERIOD_FROM行a = 28727 p = 61038 i = 1已过滤a = 100 p = 10 i = 100 a额外:在使用临时使用filesort b的地方extra:在使用联接缓冲区的地方使用(块嵌套循环)c extra:null

例如,我最好对整个年份和月份进行一次更复杂的查询,例如合并所有价格表。但是,这太慢了。我已在每个表中建立索引:DATE,PERIOD_FROM,PERIOD_UNTIL。计算结果可能不会更改,在这种情况下,每两米的季度每小时消耗量乘以每小时价格。

1 个答案:

答案 0 :(得分:0)

“从类别上来讲”,首先要看的是索引。

您的子句(例如WHERE i.DATE = a.DATE ...被归类为 INNER JOINs ,并且SQL引擎需要具有“立即”定位匹配行的能力。 (也就是说,无需查看整个表格!)

  • FYI:就像现实生活中的任何索引一样,如果我们还有这样的话,这里我将谈论“图书馆卡目录” –索引将同时帮助“等于”和“少于/大于”查询。索引将计算机直接 移至数据中的特定点,无论是“命中”还是“近失”。

最后,EXPLAIN动词非常有用:将这个词放在查询的前面,SQL引擎应该准确地如何“向您解释”它打算执行您的操作查询。 (SQL引擎查看数据库的结构以做出决定。)尽管EXPLAIN的输出是... (heh) ...“不是完全标准化的,” em>将帮助您查看计算机是否认为需要做一些非常浪费时间的事情才能提供答案。