由Subselect导致的一严重性能问题

由Subselect导致的一严重性能问题

在做自动定价流程的性能测试中,发现一个很棘手的性能问题:一个非常简单的查询跑起来非常非常慢,几乎每一秒钟只从数据库返回一条记录!数据库是zLinux Server 上的 DB2 8.5,CPU Utilization 只有 35% 而已。

花了大半天时间,最后我以为是数据库的问题(因为是由别人管理的远程数据库),SQL如此简单应该没有问题;但是从DBA的反馈是他检查了数据库的所有状态,一切正常:( 我几乎崩溃…

但今天,最终还是承认SQL确实有问题,而且犯大忌 (对查询优化的认识有待提高啊…)

-- less 1 record inserted per second, 30000 records insertion need 10 hours
-- to complete (timeout...)
INSERT INTO WWPRT.CABLEPRODUCT_PRICETYPE_JOIN_CN (CABLEPRODUCTID,
PRICETYPE, SLAVE) 
(
     SELECT cableproduct.ID, pricetypes.PRICETYPE, 'N'
     FROM WWPRT.CABLE_PRODUCT_JOIN_CN AS cableproduct,
     (
          SELECT DISTINCT usprice.PRICETYPE FROM WWPRT.PRICE_CN usprice
          JOIN WWPRT.CONF_PRICETYPE pt ON pt.ID = usprice.PRICETYPE
          WHERE usprice.CABLEID = 'USCABF3FVT01'
          AND pt.DOMAIN IN ( SELECT DISTINCT DOMAIN FROM WWPRT.CONF_GAP )
     ) AS pricetypes
     WHERE CABLEID = 'GEOANNF3FVT1'
     AND EXISTS (
         ......
     )
)


其罪魁祸首就是“from”分句中的 subselect 语句,数据库会对 WWPRT.CABLE_PRODUCT_JOIN_CN 表中的每一条记录都执行一次上面的 subselect 语句,太可怕了!修改了 SQL 如下,让上面的 subselect 部分只执行一次作为临时表:


-- 30000 records insertion only costs 9 seconds to complete!
WITH US_PRICETYPES (PRICETYPE) AS (
    SELECT DISTINCT usprice.PRICETYPE FROM WWPRT.PRICE_CN usprice
    JOIN WWPRT.CONF_PRICETYPE pt ON pt.ID = usprice.PRICETYPE
    LEFT OUTER JOIN WWPRT.CONF_GAP gap ON pt.DOMAIN = gap.DOMAIN
    WHERE usprice.CABLEID = 'USCABF3FVT01'
    AND gap.DOMAIN IS NOT NULL
)
SELECT COUNT(*) FROM NEW TABLE
(
    INSERT INTO WWPRT.CABLEPRODUCT_PRICETYPE_JOIN_CN
    (CABLEPRODUCTID, PRICETYPE, SLAVE)
    (
    SELECT cableproduct.ID, pricetypes.PRICETYPE, 'N'
    FROM WWPRT.CABLE_PRODUCT_JOIN_CN AS cableproduct,
    US_PRICETYPES AS pricetypes
    WHERE CABLEID = 'GEOANNF3FVT1'
    AND EXISTS (
        ......
    )
))

性能的改进太可怕了,需要10个小时跑完的查询10秒就结束了!尽管我用的是DB2,但我想对其它数据库应该也有这样的问题,没有验证过…

Followed:
--------------------------------------------------------------------------------------
谢谢Daniel的建议:

如果程序不关心究竟有多少条记录被插入了,可以用另一个 Fetch,而不是 Count(*),这样性能会更好:

SELECT CABLEPRODUCTID FROM NEW TABLE
(INSERT INTO WWPRT.CABLEPRODUCT_PRICETYPE_JOIN_CN (CABLEPRODUCTID,
PRICETYPE, SLAVE)
(
     SELECT cableproduct.ID, pricetypes.PRICETYPE, 'N'
     FROM WWPRT.CABLE_PRODUCT_JOIN_CN AS cableproduct,
     US_PRICETYPES AS pricetypes
     WHERE CABLEID = 'GEOANNF3FVT1'
     AND EXISTS (
         ......
     )
)) FETCH FIRST 1 ROWS ONLY

你可能感兴趣的:(由Subselect导致的一严重性能问题)