Mysql 是否可以提高此查询的性能
我在MySql服务器中有一个非常慢的查询 我添加以下查询:Mysql 是否可以提高此查询的性能,mysql,sql,performance,Mysql,Sql,Performance,我在MySql服务器中有一个非常慢的查询 我添加以下查询: SELECT CRR_DT, TOU, SRCE, SINK, NAME, SEASON, SRCESUMCONG, SINKSUMCONG, SRCEAVGCONG, SINKAVGCONG, SUMSINKMSRCE, AVGSINKMSRCE, HOURCOUNT, TERM, START_DT, END_DT, CTYPE, MW AS MW_AWARD, Mark, SCID
SELECT CRR_DT, TOU, SRCE, SINK, NAME, SEASON, SRCESUMCONG, SINKSUMCONG,
SRCEAVGCONG, SINKAVGCONG, SUMSINKMSRCE, AVGSINKMSRCE,
HOURCOUNT, TERM, START_DT, END_DT, CTYPE, MW AS MW_AWARD,
Mark, SCID
FROM
( SELECT a.CRR_DT, a.TOU, a.SRCE, a.SINK, a.NAME, a.SEASON, a.SRCESUMCONG,
a.SINKSUMCONG, a.SRCEAVGCONG, a.SINKAVGCONG, a.SUMSINKMSRCE,
a.AVGSINKMSRCE, a.HOURCOUNT, b.TERM, b.CTYPE, b.START_DT,
b.END_DT, b.MW, b.SCID, b.Mark
FROM
( SELECT CRR_DT, TOU, SRCE, SINK, NAME, SEASON, SRCESUMCONG, SINKSUMCONG,
SRCEAVGCONG, SINKAVGCONG, SUMSINKMSRCE, AVGSINKMSRCE,
HOURCOUNT
FROM CRR_CONGCALC
WHERE CRR_DT >= '2015-01'
) a
INNER JOIN
( SELECT MARKET, TERM, TOU, SRCE, SINK, NAME, SCID, CTYPE, START_DT,
END_DT, SUM(MW) AS MW, SUBSTR(MARKET, 1, 3) AS MARK
FROM CRR_INVENTORY
WHERE COPTION = 'OBLIGATION'
AND START_DT >= '2015-01-01'
AND SCID IN ('EAGL' , 'LDES')
GROUP BY MARKET , TOU , SRCE , SINK , NAME , SCID , CTYPE ,
START_DT , END_DT
) b ON a.NAME = b.NAME
AND a.TOU = b.TOU
) c
WHERE c.CRR_DT BETWEEN SUBSTR(c.START_DT, 1, 7) AND SUBSTR(c.END_DT, 1, 7 )
ORDER BY NAME , CRR_DT , TOU ASC
这里的结果是使用
我猜红色方块很危险。有人能帮我理解这个计划吗?一旦我有了这个执行计划,关于我应该检查什么的一些提示
编辑添加表布局
唤起回忆。对于数据库,“完整表扫描”意味着数据库不能使用任何东西来加速查询,它读取整个表这些行以非排序顺序存储,因此没有更好的方法“搜索”您要查找的员工id 这很糟糕。为什么? 如果您有一个包含一串列的表:
名字、姓氏、员工id,…,第50列
进行搜索,其中员工id=1234,如果员工id列上没有索引,则进行顺序扫描。如果您在表1.employee_id=table2.eid上执行联接表2,则情况更糟,因为它必须将employee_id与联接表中的每个记录相匹配
如果创建索引,则可以大大减少查找匹配项(或丢弃非匹配项)的扫描时间,因为您可以搜索排序字段,而不是执行顺序扫描。快得多
当您在employee_id字段上创建索引时,您正在创建一种搜索员工编号的方法,该方法要快得多创建索引时,您会说“我将基于此字段加入,或者基于此字段使用where子句”。这会以占用少量磁盘空间为代价加快查询速度
索引有各种各样的技巧,你可以创建它们,使它们是唯一的,而不是唯一的,复合的(包含多个列)和各种各样的东西。发布您的查询,我们可以告诉您,为了加快速度,您可能会在索引方面做些什么
一个好的经验法则是,应该在where子句、联接条件或order by中使用的字段上的表上创建索引。选择字段取决于一些超出了本文讨论范围的事情,但这应该是一个开始。让人回忆起来。对于数据库,“完整表扫描”意味着数据库不能使用任何东西来加速查询,它读取整个表这些行以非排序顺序存储,因此没有更好的方法“搜索”您要查找的员工id
这很糟糕。为什么?
如果您有一个包含一串列的表:
名字、姓氏、员工id,…,第50列
进行搜索,其中员工id=1234
,如果员工id列上没有索引,则进行顺序扫描。如果您在表1.employee_id=table2.eid上执行联接表2,则情况更糟,因为它必须将employee_id与联接表中的每个记录相匹配
如果创建索引,则可以大大减少查找匹配项(或丢弃非匹配项)的扫描时间,因为您可以搜索排序字段,而不是执行顺序扫描。快得多
当您在employee_id字段上创建索引时,您正在创建一种搜索员工编号的方法,该方法要快得多创建索引时,您会说“我将基于此字段加入,或者基于此字段使用where子句”。这会以占用少量磁盘空间为代价加快查询速度
索引有各种各样的技巧,你可以创建它们,使它们是唯一的,而不是唯一的,复合的(包含多个列)和各种各样的东西。发布您的查询,我们可以告诉您,为了加快速度,您可能会在索引方面做些什么
一个好的经验法则是,应该在where子句、联接条件或order by中使用的字段上的表上创建索引。选择字段取决于一些超出本讨论范围的事情,但这应该是一个开始。
- 从(选择…)连接(选择…)到…
的模式没有很好地优化。查看是否可以直接从其中一个表转到,而不是将其隐藏在子查询中
CRR\u CONGCALC
需要索引(CRR\u DT)
。(请提供显示创建表)
CRR\u库存
需要索引(COPION,START\u DT)
- 从(选择…)连接(选择…)到…的模式没有很好地优化。查看是否可以直接从其中一个表转到,而不是将其隐藏在子查询中
需要CRR\u CONGCALC
。(请提供索引(CRR\u DT)
显示创建表
)
需要CRR\u库存
索引(COPION,START\u DT)
如果需要,请进行这些更改,然后回来寻求更多建议。根据您的解释图,在
CRR\u CONGCALC
和CRR\u INVENTORY
上的每个子查询都会进行完整的表扫描。然后,当您将子查询连接在一起时,再进行一次完整表扫描,最后,当结果集排序时,再进行一次完整表扫描
提高性能的几个技巧
CREATE TABLE `CRR_CONGCALC` (
`CRR_DT` varchar(7) NOT NULL,
`TOU` varchar(50) NOT NULL,
`SRCE` varchar(50) NOT NULL,
`SINK` varchar(50) NOT NULL,
`SRCESUMCONG` decimal(12,6) DEFAULT NULL,
`SINKSUMCONG` decimal(12,6) DEFAULT NULL,
`SRCEAVGCONG` decimal(12,6) DEFAULT NULL,
`SINKAVGCONG` decimal(12,6) DEFAULT NULL,
`SUMSINKMSRCE` decimal(12,6) DEFAULT NULL,
`AVGSINKMSRCE` decimal(12,6) DEFAULT NULL,
`HOURCOUNT` int(11) NOT NULL DEFAULT '0',
`SEASON` char(1) NOT NULL DEFAULT '0',
`NAME` varchar(110) NOT NULL,
PRIMARY KEY (`CRR_DT`,`SRCE`,`SINK`,`TOU`,`HOURCOUNT`),
KEY `srce_index` (`SRCE`),
KEY `srcesink` (`SRCE`,`SINK`)
)
CREATE TABLE `CRR_INVENTORY` (
`MARKET` varchar(50) NOT NULL,
`TERM` varchar(50) NOT NULL,
`TOU` varchar(50) NOT NULL,
`INVENTORY_DT` date NOT NULL,
`START_DT` datetime NOT NULL,
`END_DT` datetime NOT NULL,
`CRR_ID` varchar(50) NOT NULL,
`NSR_INDEX` tinyint(1) NOT NULL,
`SEGMENT` tinyint(1) NOT NULL,
`CTYPE` varchar(50) NOT NULL,
`CATEGORY` varchar(50) NOT NULL,
`COPTION` varchar(50) NOT NULL,
`SRCE` varchar(50) DEFAULT NULL,
`SINK` varchar(50) DEFAULT NULL,
`MW` decimal(8,4) NOT NULL,
`SCID` varchar(50) NOT NULL,
`SEASON` char(1) DEFAULT '0',
`NAME` varchar(110) NOT NULL,
PRIMARY KEY (`MARKET`,`INVENTORY_DT`,`CRR_ID`),
KEY `srcesink` (`SRCE`,`SINK`)
)
c.CRR_DT BETWEEN SUBSTR(c.START_DT, 1, 7) AND SUBSTR(c.END_DT, 1, 7)
DATE_FORMAT(<FIELD>, '%Y-%m-01')
SELECT CAST('2015-07-05' AS DATETIME) between '2015-07' and '2015-07';
-- This query returns 0 == False.
CREATE TABLE sub_a (KEY(CRR_DT), KEY(NAME), KEY(TOU), KEY(NAME, TOU)) AS
SELECT CRR_DT,
TOU,
SRCE,
SINK,
NAME,
SEASON,
SRCESUMCONG,
SINKSUMCONG,
SRCEAVGCONG,
SINKAVGCONG,
SUMSINKMSRCE,
AVGSINKMSRCE,
HOURCOUNT
FROM CRR_CONGCALC
WHERE CRR_DT >= '2015-01-01';
CREATE TABLE sub_b (KEY(NAME), KEY(TOU), KEY(NAME, TOU)) AS
SELECT MARKET,
TERM,
TOU,
SRCE,
SINK,
NAME,
SCID,
CTYPE,
START_DT,
END_DT,
SUM(MW) AS MW_AWARD,
SUBSTR(MARKET,1,3) AS MARK
FROM CRR_INVENTORY
WHERE COPTION = 'OBLIGATION'
AND START_DT >= '2015-01-01'
AND SCID IN ('EAGL','LDES')
GROUP BY MARKET, TERM, TOU,
SRCE, SINK, NAME, SCID,
CTYPE, START_DT, END_DT, MARK
-- note the two added columns in the groupby clause.
SELECT a.CRR_DT,
a.TOU,
a.SRCE,
a.SINK,
a.NAME,
a.SEASON,
a.SRCESUMCONG,
a.SINKSUMCONG,
a.SRCEAVGCONG,
a.SINKAVGCONG,
a.SUMSINKMSRCE,
a.AVGSINKMSRCE,
a.HOURCOUNT,
b.TERM,
b.CTYPE,
b.START_DT,
b.END_DT,
b.MW_AWARD,
b.SCID,
b.Mark
FROM sub_a a
JOIN sub_b b ON a.NAME = b.NAME AND a.TOU = b.TOU
WHERE a.CRR_DT BETWEEN DATE_FORMAT(b.START_DT,'%Y-%m-01')
AND DATE_FORMAT(b.END_DT,'%Y-%m-01')
ORDER BY NAME,
CRR_DT,
TOU;
WHERE sub_a.CRR_DT BETWEEN DATE_FORMAT(sub_b.START_DT,'%Y-%m-01')
AND DATE_FORMAT(DATE_ADD(sub_b.END_DT, INTERVAL 1 MONTH),'%Y-%m-01')
SELECT t.foo
FROM mytable t
WHERE t.foo = 'bar'
SELECT t.foo
FROM (SELECT * FROM mytable) t
WHERE t.foo = 'bar'
SELECT t.foo
FROM (SELECT * FROM mytable WHERE foo = 'bar') t
SELECT c.crr_dt
, c.tou
, c.srce
, c.sink
, c.name
, c.season
, c.srcesumcong
, c.sinksumcong
, c.srceavgcong
, c.sinkavgcong
, c.sumsinkmsrce
, c.avgsinkmsrce
, c.hourcount
, b.term
, b.start_dt
, b.end_dt
, b.ctype
, b.mw AS mw_award
, b.scid
, b.mark
FROM CRR_CONGCALC c
JOIN ( SELECT i.market
, i.term
, i.tou
, i.srce
, i.sink
, i.name
, i.scid
, i.ctype
, i.start_dt
, i.end_dt
, SUM(i.mw) AS mw
, SUBSTR(i.market, 1, 3) AS mark
FROM CRR_INVENTORY i
WHERE i.coption = 'OBLIGATION'
AND i.start_dt >= '2015-01-01'
AND i.scid IN ('EAGL','LDES')
GROUP
BY i.market
, i.tou
, i.srce
, i.sink
, i.name
, i.scid
, i.ctype
, i.start_dt
, i.end_dt
) b
ON c.name = b.name
AND c.tou = b.tou
AND c.crr_dt >= '2015-01'
AND c.crr_dt BETWEEN SUBSTR(b.start_dt,1,7)
AND SUBSTR(b.end_dt,1,7)
ORDER
BY c.name
, c.crr_dt
, c.tou
AND c.crr_dt BETWEEN DATE_FORMAT(b.start_dt,'%Y-%m') AND DATE_FORMAT(b.end_dt,'%Y-%m')
ON c.name = b.name
AND c.tou = b.tou
AND c.crr_dt >= '2015-01'
AND c.crr_dt BETWEEN SUBSTR(b.start_dt,1,7)
AND SUBSTR(b.end_dt,1,7)