需要加快MySQL查询速度

时间:2017-01-29 13:38:54

标签: mysql

我有一个查询用于获取各种输入来计算资产排名。为了获得基于用户输入计算资产等级的各种值,我使用多个子查询到单个表。但这花费了太多时间。任何人都可以帮我改进这个查询吗?

 SELECT AssetId,
       AssetName,
       Isin,

  (SELECT DClose
   FROM eod_data
   WHERE Isin=a.Isin
     AND DDate >= now()-interval 12 MONTH
   ORDER BY DDate ASC LIMIT 1) AS rafval,

  (SELECT DClose
   FROM eod_data
   WHERE Isin=a.Isin
     AND DDate >= now()-interval 12 MONTH
   ORDER BY DDate DESC LIMIT 1) AS ralval,

  (SELECT DClose
   FROM eod_data
   WHERE Isin=a.Isin
     AND DDate >= now()-interval 3 MONTH
   ORDER BY DDate ASC LIMIT 1) AS rbfval,

  (SELECT DClose
   FROM eod_data
   WHERE Isin=a.Isin
     AND DDate >= now()-interval 3 MONTH
   ORDER BY DDate DESC LIMIT 1) AS rblval,

  (SELECT DClose
   FROM eod_data
   WHERE Isin=a.Isin
     AND DDate >= now()-interval 20 DAY
   ORDER BY DDate ASC LIMIT 1) AS rcfval,

  (SELECT DClose
   FROM eod_data
   WHERE Isin=a.Isin
     AND DDate >= now()-interval 20 DAY
   ORDER BY DDate DESC LIMIT 1) AS rclval,

  (SELECT STD(DClose)
   FROM eod_data
   WHERE Isin=a.Isin
     AND DDate >= now()-interval 20 DAY
   ORDER BY DDate DESC LIMIT 1) AS vstd
FROM assets a
INNER JOIN assetclasses ac ON ac.AssetClassId=a.AssetClassId
INNER JOIN assetsubgroups asg ON asg.AssetSubGroupId=ac.AssetSubGroupId
WHERE asg.AssetGroupId=1
  AND a.IsActive=1;

在上面的查询中,子查询中提到的所有区间都是变量。它们来自用户输入。包含1000个资产的资产表和eod_data将包含数百万条记录。

我也为涉及where子句的所有字段创建了索引。

表格结构 assets:AssetId,AssetName,Isin,IsActive | eod_data:Isin,DClose,DDate

上述查询大约需要11分钟。

提前致谢。

请在此处找到示例数据库http://sqlfiddle.com/#!9/d0a50/3

2 个答案:

答案 0 :(得分:1)

你可以试试这个查询吗?它只对所有列使用一个Join,但是对于您的示例数据,最后一个字段每次都为null,也与您的查询一致。

SELECT
      AssetId
    , AssetName
    , a.Isin
    , min(IF(DDate >= now()-interval 12 MONTH, DClose,null) )  AS rafval
    , max(IF(DDate >= now()-interval 12 MONTH, DClose,null) )  AS ralval
    , min(IF(DDate >= now()-interval 3 MONTH,  DClose,null) )  AS rbfval
    , max(IF(DDate >= now()-interval 3 MONTH,  DClose,null) )  AS rblval
    , min(IF(DDate >= now()-interval 20 DAY,   DClose,null) )  AS rcfval
    , max(IF(DDate >= now()-interval 20 DAY,   DClose,null) )  AS rclval
    , STD(IF(DDate >= now()-interval 20 DAY,   DClose,null) )  AS vstd
FROM assets a
INNER JOIN assetclasses ac ON ac.AssetClassId=a.AssetClassId
INNER JOIN assetsubgroups asg ON asg.AssetSubGroupId=ac.AssetSubGroupId
LEFT JOIN eod_data ed ON ed.Isin = a.Isin

WHERE asg.AssetGroupId=1
  AND a.IsActive=1
  GROUP BY AssetId;

<强>样品

MariaDB [test]> SELECT
    ->       AssetId
    ->     , AssetName
    ->     , a.Isin
    ->     , min(IF(DDate >= now()-interval 12 MONTH, DClose,null) )  AS rafval
    ->     , max(IF(DDate >= now()-interval 12 MONTH, DClose,null) )  AS ralval
    ->     , min(IF(DDate >= now()-interval 3 MONTH,  DClose,null) )  AS rbfval
    ->     , max(IF(DDate >= now()-interval 3 MONTH,  DClose,null) )  AS rblval
    ->     , min(IF(DDate >= now()-interval 20 DAY,   DClose,null) )  AS rcfval
    ->     , max(IF(DDate >= now()-interval 20 DAY,   DClose,null) )  AS rclval
    ->     , STD(IF(DDate >= now()-interval 20 DAY,   DClose,null) )  AS vstd
    -> FROM assets a
    -> INNER JOIN assetclasses ac ON ac.AssetClassId=a.AssetClassId
    -> INNER JOIN assetsubgroups asg ON asg.AssetSubGroupId=ac.AssetSubGroupId
    -> LEFT JOIN eod_data ed ON ed.Isin = a.Isin
    ->
    -> WHERE asg.AssetGroupId=1
    ->   AND a.IsActive=1
    ->   GROUP BY AssetId;
+---------+---------------------+---------+----------+----------+----------+----------+--------+--------+------+
| AssetId | AssetName           | Isin    | rafval   | ralval   | rbfval   | rblval   | rcfval | rclval | vstd |
+---------+---------------------+---------+----------+----------+----------+----------+--------+--------+------+
|       1 | AT ANDRITZ          | ANDR_AT | 97.5700  | 97.5700  | 97.5700  | 97.5700  | NULL   | NULL   | NULL |
|       5 | AT BWT              | BWTV_AT | 98.2000  | 98.2000  | 98.2000  | 98.2000  | NULL   | NULL   | NULL |
|       6 | AT ERSTE GROUP BANK | ERST_AT | 99.8000  | 99.8000  | 99.8000  | 99.8000  | NULL   | NULL   | NULL |
|       7 | AT EVN              | EVNV_AT | 99.2600  | 99.2600  | 99.2600  | 99.2600  | NULL   | NULL   | NULL |
|       8 | AT FLUGHAFEN WIEN   | VIEV_AT | 102.5200 | 102.5200 | 102.5200 | 102.5200 | NULL   | NULL   | NULL |
|      10 | AT IMMOFINANZ       | IMFI_AT | 104.1600 | 104.1600 | 104.1600 | 104.1600 | NULL   | NULL   | NULL |
|      11 | AT LENZING          | LENV_AT | 103.1300 | 103.1300 | 103.1300 | 103.1300 | NULL   | NULL   | NULL |
|      12 | AT MAYR MELNHOF     | MMKV_AT | 104.3700 | 104.3700 | 104.3700 | 104.3700 | NULL   | NULL   | NULL |
|      13 | AT MEINL EUR LAND   | MELV_AT | 103.0300 | 103.0300 | 103.0300 | 103.0300 | NULL   | NULL   | NULL |
|      14 | AT OMV              | OMVV_AT | 102.7200 | 102.7200 | 102.7200 | 102.7200 | NULL   | NULL   | NULL |
|      15 | AT PALFINGER        | PALF_AT | 101.2000 | 101.2000 | 101.2000 | 101.2000 | NULL   | NULL   | NULL |
|      17 | AT RHI AG           | RHIV_AT | 98.7800  | 98.7800  | 98.7800  | 98.7800  | NULL   | NULL   | NULL |
|      18 | AT SCHOELLER-BLECK  | SBOE_AT | 98.2100  | 98.2100  | 98.2100  | 98.2100  | NULL   | NULL   | NULL |
|      19 | AT SEMPERIT HDG     | SMPV_AT | 98.4500  | 98.4500  | 98.4500  | 98.4500  | NULL   | NULL   | NULL |
|      20 | AT TELEKOM AUSTRIA  | TELA_AT | 97.7400  | 97.7400  | 97.7400  | 97.7400  | NULL   | NULL   | NULL |
+---------+---------------------+---------+----------+----------+----------+----------+--------+--------+------+
15 rows in set (0.00 sec)

MariaDB [test]>

答案 1 :(得分:1)

这是我的下一次尝试。我测试了一些不同的连接。这是快速的方式(快1400倍)。 STD()列暂时未实现。可以请检查其他输出是否正确

..和STD决赛(我希望)。

SELECT 
    a.AssetId
    , a.AssetName
    , a.Isin
    , CAST(COALESCE(ed2.DClose,0) AS DECIMAL(20,4)) AS rafval
    , CAST(COALESCE(ed3.DClose,0) AS DECIMAL(20,4)) AS ralval
    , CAST(COALESCE(ed4.DClose,0) AS DECIMAL(20,4)) AS rbfval
    , CAST(COALESCE(ed5.DClose,0) AS DECIMAL(20,4)) AS rblval
    , CAST(COALESCE(ed6.DClose,0) AS DECIMAL(20,4)) AS rcfval
    , CAST(COALESCE(ed7.DClose,0) AS DECIMAL(20,4)) AS rclval
    , COALESCE(ed.vstd,0) AS vstd
FROM (
    SELECT  
    ed.Isin
        , MIN(IF( DDate >= now()-INTERVAL 12 MONTH, EodDataId, NULL)) AS id_rafval
        , MAX(IF( DDate >= now()-INTERVAL 12 MONTH, EodDataId, NULL)) AS id_ralval
        , MIN(IF( DDate >= now()-INTERVAL  3 MONTH, EodDataId, NULL)) AS id_rbfval
        , MAX(IF( DDate >= now()-INTERVAL  3 MONTH, EodDataId, NULL)) AS id_rblval
        , MIN(IF( DDate >= now()-INTERVAL 40 DAY  , EodDataId, NULL)) AS id_rcfval
        , MAX(IF( DDate >= now()-INTERVAL 40 DAY  , EodDataId, NULL)) AS id_rclval
        , std(IF( DDate >= now()-INTERVAL 40 DAY  , NULL, DClose )) AS vstd
    FROM eod_data ed
    WHERE ed.DDate >= now()-INTERVAL 12 MONTH
    GROUP BY ed.Isin
    ORDER BY ed.EodDataId ASC
    ) ed
LEFT JOIN eod_data ed2 ON ed2.Isin = ed.Isin AND ed2.EodDataId = ed.id_rafval
LEFT JOIN eod_data ed3 ON ed3.Isin = ed.Isin AND ed3.EodDataId = ed.id_ralval
LEFT JOIN eod_data ed4 ON ed4.Isin = ed.Isin AND ed4.EodDataId = ed.id_rbfval
LEFT JOIN eod_data ed5 ON ed5.Isin = ed.Isin AND ed5.EodDataId = ed.id_rblval
LEFT JOIN eod_data ed6 ON ed6.Isin = ed.Isin AND ed6.EodDataId = ed.id_rcfval
LEFT JOIN eod_data ed7 ON ed7.Isin = ed.Isin AND ed7.EodDataId = ed.id_rclval
INNER JOIN assets a ON a.Isin = ed.Isin
INNER JOIN assetclasses ac ON ac.AssetClassId=a.AssetClassId
INNER JOIN assetsubgroups asg ON asg.AssetSubGroupId=ac.AssetSubGroupId
WHERE asg.AssetGroupId=1
  AND a.IsActive=1
ORDER BY a.AssetId;
SELECT 
    a.AssetId
    , a.AssetName
    , a.Isin
    , CAST(COALESCE(ed2.DClose,0) AS DECIMAL(20,4)) AS rafval
    , CAST(COALESCE(ed3.DClose,0) AS DECIMAL(20,4)) AS ralval
    , CAST(COALESCE(ed4.DClose,0) AS DECIMAL(20,4)) AS rbfval
    , CAST(COALESCE(ed5.DClose,0) AS DECIMAL(20,4)) AS rblval
    , CAST(COALESCE(ed6.DClose,0) AS DECIMAL(20,4)) AS rcfval
    , CAST(COALESCE(ed7.DClose,0) AS DECIMAL(20,4)) AS rclval
FROM (
    SELECT  
    ed.Isin
        , MIN(IF( DDate >= now()-INTERVAL 12 MONTH, EodDataId, NULL)) AS id_rafval
        , MAX(IF( DDate >= now()-INTERVAL 12 MONTH, EodDataId, NULL)) AS id_ralval
        , MIN(IF( DDate >= now()-INTERVAL  3 MONTH, EodDataId, NULL)) AS id_rbfval
        , MAX(IF( DDate >= now()-INTERVAL  3 MONTH, EodDataId, NULL)) AS id_rblval
        , MIN(IF( DDate >= now()-INTERVAL 20 DAY  , EodDataId, NULL)) AS id_rcfval
        , MAX(IF( DDate >= now()-INTERVAL 20 DAY  , EodDataId, NULL)) AS id_rclval
    FROM eod_data ed
    WHERE ed.DDate >= now()-INTERVAL 12 MONTH
    GROUP BY ed.Isin
    ORDER BY ed.DDate ASC
    ) ed
LEFT JOIN eod_data ed2 ON ed2.Isin = ed.Isin AND ed2.EodDataId = ed.id_rafval
LEFT JOIN eod_data ed3 ON ed3.Isin = ed.Isin AND ed3.EodDataId = ed.id_ralval
LEFT JOIN eod_data ed4 ON ed4.Isin = ed.Isin AND ed4.EodDataId = ed.id_rbfval
LEFT JOIN eod_data ed5 ON ed5.Isin = ed.Isin AND ed5.EodDataId = ed.id_rblval
LEFT JOIN eod_data ed6 ON ed6.Isin = ed.Isin AND ed6.EodDataId = ed.id_rcfval
LEFT JOIN eod_data ed7 ON ed7.Isin = ed.Isin AND ed7.EodDataId = ed.id_rclval
INNER JOIN assets a ON a.Isin = ed.Isin
INNER JOIN assetclasses ac ON ac.AssetClassId=a.AssetClassId
INNER JOIN assetsubgroups asg ON asg.AssetSubGroupId=ac.AssetSubGroupId
WHERE asg.AssetGroupId=1
  AND a.IsActive=1
ORDER BY a.AssetId;

你可以再试一次吗?