MySQL视图优化心得

为了获取客户购买的设备通道,需要编写一个视图,视图用到的数据表共7个,表及其关联关系如下表所示。

实体

名称

缩写

实体关系

关联关系

CUST

客户

C

 

 

PU

前端设备

P

 

 

CAPABILITY

资源服务目录(业务能力)

CAP

 

 

VIDEO_IN_CHANNEL

视频输入通道

V

1P

1V.PU_SEQUENCE_ID = P.PU_SEQUENCE_ID

BUYCHANNEL

客户购买通道

BC

1C
2
P
3
V
4
R

1BC.CUST_ID = C.CUST_ID
2
BC.PU_EQUIP_CODE = P.PU_EQUIP_CODE
3
BC.PU_EQUIP_CODE = P.PU_EQUIP_CODE
   BC.VIDEO_IN_PORT = V.VIDEO_IN_PORT
   V.PU_SEQUENCE_ID = P.PU_SEQUENCE_ID
4
BC.REGION_ID = R.REGION_ID

CORP_CUST_CAPABILITY

企业客户业务能力

CCC

1C

1CCC.CUST_ID = C.CUST_ID
2
CCC.CAPABILITY_ID = CAP.CAPABILITY

CAPABILITY_ATTR

业务能力属性

CA

1CCC

1CA.CUST_CAPABILITY_ID = CCC.CUST_CAPABILITY_ID

在上表关联关系的指引下,很快搞定了视图,代码如下:

 CREATE OR REPLACE VIEW QUERRY_DEVICEPORT_VIEW AS SELECT C.CUST_CODE, C.CUST_NAME, BC.PU_EQUIP_CODE, BC.OPERRIGHT, P.DEVICE_NAME, COALESCE(P.STATE, 113) AS STATE, BC.VIDEO_IN_PORT, V.VIDEO_IN_NAME, COALESCE(C.ONLINE_STATE, '0') AS ONLINE_STATE, C.EXTEND_PASSWORD_FLAG, _gb2312'5' AS ORDER_STATE, CA.ATTR_VALUE FROM CUST C, BUYCHANNEL BC, PU P, VIDEOINCHANNEL V, CORP_CUST_CAPABILITY CCC, CAPABILITY CAP, CAPABILITY_ATTR CA WHERE C.CUST_TYPE = '0' AND C.STATE IN ('0', '1') AND C.PARENT_ID IS NULL AND C.CUST_CODE IS NOT NULL AND BC.CUST_ID = C.CUST_ID AND P.DEVICE_TYPE <> '04' AND P.PU_SEQUENCE_ID = V.PU_SEQUENCE_ID AND BC.PU_EQUIP_CODE = P.PU_EQUIP_CODE AND BC.VIDEO_IN_PORT = V.VIDEO_IN_PORT AND CAP.CAPABILITY_SEQUENCE = '5' AND C.CUST_ID = CCC.CUST_ID AND CCC.CUST_CAPABILITY_ID = CA.CUST_CAPABILITY_ID AND CCC.CAPABILITY_ID = CAP.CAPABILITY_ID UNION ALL SELECT C.CUST_CODE, C.CUST_NAME, BC.PU_EQUIP_CODE, BC.OPERRIGHT, P.DEVICE_NAME, COALESCE(P.STATE, 113) AS STATE, BC.VIDEO_IN_PORT, V.VIDEO_IN_NAME, COALESCE(C.ONLINE_STATE, '0') AS ONLINE_STATE, C.EXTEND_PASSWORD_FLAG, _gb2312'5' AS ORDER_STATE, CA.ATTR_VALUE FROM CUST C, CUST PC, BUYCHANNEL BC, PU P, VIDEOINCHANNEL V, CORP_CUST_CAPABILITY CCC, CAPABILITY CAP, CAPABILITY_ATTR CA WHERE C.CUST_TYPE = '0' AND C.STATE IN ('0', '1') AND C.PARENT_ID IS NOT NULL AND C.CUST_CODE IS NOT NULL AND PC.CUST_TYPE = '0' AND PC.STATE IN ('0', '1') AND PC.PARENT_ID IS NULL AND PC.CUST_CODE IS NOT NULL AND C.PARENT_ID = PC.CUST_ID AND BC.CUST_ID = PC.CUST_ID AND P.DEVICE_TYPE <> '04' AND P.PU_SEQUENCE_ID = V.PU_SEQUENCE_ID AND BC.PU_EQUIP_CODE = P.PU_EQUIP_CODE AND BC.VIDEO_IN_PORT = V.VIDEO_IN_PORT AND CAP.CAPABILITY_SEQUENCE = '5' AND PC.CUST_ID = CCC.CUST_ID AND CCC.CUST_CAPABILITY_ID = CA.CUST_CAPABILITY_ID AND CCC.CAPABILITY_ID = CAP.CAPABILITY_ID

 

心中那个得意啊,“我得意地笑,我得意地笑”,呵呵~~。赶紧把视图贴到海豚(MySQL的一个客户端,SQLyog)里面,F8刷入数据库。接下来,加设备,加客户,划设备,折腾了半天,终于轮到数据库中的视图小试牛刀了,俺心中那个期待啊~~CTRL + T,在海豚里面打开一个新的查询窗口,瞬间敲入熟悉的SQL

SELECT * FROM QUERRY_DEVICEPORT_VIEW

F8,期待结果列表的出现……1秒钟过去了,2秒钟过去了,……,平时欢快活跃的海豚,今天一反常态,变得出奇的安静!终于,结果出来了,81984条记录,用时3312毫秒!!!我不由倒抽一口凉气,如此的查询速度,等到结果出来,恐怕黄花菜都凉了,谁还愿意用呢?

CREATE OR REPLACE ALGORITHM = MERGE VIEW QUERRY_DEVICEPORT_VIEW AS SELECT C.CUST_CODE, C.CUST_NAME, BC.PU_EQUIP_CODE, BC.OPERRIGHT, P.DEVICE_NAME, COALESCE(P.STATE, 113) AS STATE, BC.VIDEO_IN_PORT, V.VIDEO_IN_NAME, COALESCE(C.ONLINE_STATE, '0') AS ONLINE_STATE, C.EXTEND_PASSWORD_FLAG, _gb2312 '5' AS ORDER_STATE, CA.ATTR_VALUE FROM CAPABILITY CAP, CORP_CUST_CAPABILITY CCC, CAPABILITY_ATTR CA, CUST C, BUYCHANNEL BC, PU P, VIDEOINCHANNEL V WHERE CAP.CAPABILITY_SEQUENCE = '5' AND C.CUST_TYPE = '0' AND C.STATE IN ('0', '1') AND C.PARENT_ID IS NULL AND C.CUST_CODE IS NOT NULL AND P.DEVICE_TYPE <> '04' AND CAP.CAPABILITY_ID = CCC.CAPABILITY_ID AND CA.CUST_CAPABILITY_ID = CCC.CUST_CAPABILITY_ID AND CCC.CUST_ID = C.CUST_ID AND C.CUST_ID = BC.CUST_ID AND BC.PU_EQUIP_CODE = P.PU_EQUIP_CODE AND V.PU_SEQUENCE_ID = P.PU_SEQUENCE_ID AND BC.VIDEO_IN_PORT = V.VIDEO_IN_PORT UNION ALL SELECT C.CUST_CODE, C.CUST_NAME, BC.PU_EQUIP_CODE, BC.OPERRIGHT, P.DEVICE_NAME, COALESCE(P.STATE, 113) AS STATE, BC.VIDEO_IN_PORT, V.VIDEO_IN_NAME, COALESCE(C.ONLINE_STATE, '0') AS ONLINE_STATE, C.EXTEND_PASSWORD_FLAG, _gb2312 '5' AS ORDER_STATE, CA.ATTR_VALUE FROM CAPABILITY CAP, CORP_CUST_CAPABILITY CCC, CAPABILITY_ATTR CA, CUST PC, CUST C, BUYCHANNEL BC, PU P, VIDEOINCHANNEL V WHERE CAP.CAPABILITY_SEQUENCE = '5' AND PC.CUST_TYPE = '0' AND PC.STATE IN ('0', '1') AND PC.PARENT_ID IS NULL AND PC.CUST_CODE IS NOT NULL AND C.CUST_TYPE = '0' AND C.STATE IN ('0', '1') AND C.PARENT_ID IS NOT NULL AND C.CUST_CODE IS NOT NULL AND P.DEVICE_TYPE <> '04' AND CAP.CAPABILITY_ID = CCC.CAPABILITY_ID AND CCC.CUST_CAPABILITY_ID = CA.CUST_CAPABILITY_ID AND CCC.CUST_ID = PC.CUST_ID AND PC.CUST_ID = C.PARENT_ID AND PC.CUST_ID = BC.CUST_ID AND P.PU_EQUIP_CODE = BC.PU_EQUIP_CODE AND P.PU_SEQUENCE_ID = V.PU_SEQUENCE_ID AND BC.VIDEO_IN_PORT = V.VIDEO_IN_PORT

EXPLAIN、百度、谷歌……,经过一番折腾,性能的调整似乎有了眉目……

首先,对视图中关键的JOIN POINT建立索引,然后,调整表的查询顺序,记录少的表尽量往前提,再然后,把常量条件,能够减少记录的条件统统提到前面……

 

 

 

将修改过的视图刷入数据库,再次SELECT *测试,性能有所提高,时间缩短到1703毫秒。心中那个欣喜啊~~呵呵~无以言表,但是,转眼间,不免又紧张起来——查询的时间仍然大于1秒,这样的性能还是不符合要求的。

优化的初步成功,给我强烈地信心,仿佛问题的终极解决近在咫尺。把视图仔细的看了一遍,直觉告诉我问题的关键在于那个刺眼的UNION ALL操作,根据MySQL操作手册中的叙述,但凡包含UNION ALL的视图,MySQL几乎是无法做优化的,另外,UNION的第二部分SQL中对PC的关联似乎多余,视图可以进一步简化,甚至可以用一个SQL搞定。

基于上面的直觉,我决定乘胜追击,对视图再次进行调整,这里,要感谢特别原来做湖北电信经分项目开发过程中的知识积累,呵呵~

CREATE OR REPLACE ALGORITHM = MERGE VIEW QUERRY_DEVICEPORT_VIEW AS SELECT C.CUST_CODE, C.CUST_NAME, BC.PU_EQUIP_CODE, BC.OPERRIGHT, P.DEVICE_NAME, COALESCE(P.STATE, 113) AS STATE, BC.VIDEO_IN_PORT, V.VIDEO_IN_NAME, COALESCE(C.ONLINE_STATE, '0') AS ONLINE_STATE, C.EXTEND_PASSWORD_FLAG, _gb2312 '5' AS ORDER_STATE, CA.ATTR_VALUE FROM CAPABILITY CAP, CORP_CUST_CAPABILITY CCC, CAPABILITY_ATTR CA, CUST C, PU P, VIDEOINCHANNEL V, BUYCHANNEL BC WHERE CAP.CAPABILITY_SEQUENCE = '5' AND C.CUST_TYPE = '0' AND C.STATE IN ('0', '1') AND C.CUST_CODE IS NOT NULL AND CAP.CAPABILITY_ID = CCC.CAPABILITY_ID AND CA.CUST_CAPABILITY_ID = CCC.CUST_CAPABILITY_ID AND (CASE WHEN C.PARENT_ID IS NULL THEN CCC.CUST_ID = C.CUST_ID ELSE CCC.CUST_ID = C.PARENT_ID END) AND (CASE WHEN C.PARENT_ID IS NULL THEN C.CUST_ID = BC.CUST_ID ELSE C.PARENT_ID = BC.CUST_ID END) AND P.PU_SEQUENCE_ID = V.PU_SEQUENCE_ID AND BC.PU_EQUIP_CODE = P.PU_EQUIP_CODE AND BC.VIDEO_IN_PORT = V.VIDEO_IN_PORT

“没有最快,只有更快”,赶紧把视图刷入数据库,回到刚才的查询窗口,按下F8,执行SELECT *查询,哈哈~~哈哈~~哈哈~~~~91984条记录,93毫秒!!搞定了~~搞定了!!感谢奋进,感谢党,感谢政府,感谢伟大的中华人民共和国,感谢父母,感谢老婆,哈哈~~~

这次优化,主要是根据EXPLAIN来分析SQL语句的执行计划,对关键的条件加上索引。另外,MySQL操作手册中有一段话让我决定把小表放在JOIN的前面:“MySQL resolves all joins using a single-sweep multi-join method. This means that MySQL reads a row from the first table, and then finds a matching row in the second table, the third table, and so on. When all tables are processed, MySQL outputs the selected columns and backtracks through the table list until a table is found for which there are more matching rows. The next row is read from this table and the process continues with the next table.”。再有的就是,能够不用UNIONGROUP BY的地方,尽量不用。

 

 

你可能感兴趣的:(数据库技术,mysql,null,table,数据库,优化,merge)