需要加快MySQL查询速度吗

需要加快MySQL查询速度吗,mysql,Mysql,我有一个查询,用于获取各种输入以计算资产排名。为了获得基于用户输入计算资产等级的各种值,我对单个表使用了多个子查询。但这花费了太多的时间。有人能帮我临时提出这个问题吗 SELECT AssetId, AssetName, Isin, (SELECT DClose FROM eod_data WHERE Isin=a.Isin AND DDate >= now()-interval 12 MONTH ORDER BY DDate

我有一个查询,用于获取各种输入以计算资产排名。为了获得基于用户输入计算资产等级的各种值,我对单个表使用了多个子查询。但这花费了太多的时间。有人能帮我临时提出这个问题吗

 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_数据,将包含数百万条记录

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

表结构 资产:资产名称、资产名称、Isin、IsActive eod_数据:Isin、DClose、DDate

上面的查询大约需要11分钟

提前谢谢


请在此处找到示例数据库

您可以尝试此查询吗。它只对所有列使用一个联接,但对于示例数据,最后一个字段每次都为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]>

这是我的下一次尝试。我测试了一些不同的连接。这是最快的方式(快1400倍)。STD()列未在矩中实现。你能检查一下其他输出是否正确吗

…和最后的STD()(我希望)


你能再测试一下吗?

有两个表的样本日期和创建日期吗?@Bernd Buffen感谢你的快速回复。现在我没有任何样本数据。我会创造一些东西。您需要它来检查数据格式还是测试查询?所以我将创建样本表好的,你可以把我放在上面,你可以把表和样本数据放在上面,再次感谢你的回复。实际上这里对于rafval,我需要该时间间隔的第一天值,对于ralval,我需要该时间间隔的最后一天值。。。类似的还有子查询。它不是最小值或最大值。关于样本数据,是的,它没有足够的数据进行所有计算。但是请不要介意,给我一些类似这样的想法,在查询中获取第一个和最后一个值来代替最小值和最大值。谢谢抱歉-min和max必须是正确的。如果你说min,你得到的是最低的日期,min中有一个if语句,它将通过范围中的一个日期。这不对吗?很抱歉,它没有返回该日期间隔中的第一个和最后一个值。它只返回最小值和最大值。还有一件事,我用真实数据检查了数据库的性能。与该查询匹配的总资产为1550个,需要584.754s。我添加了更多数据以满足所有条件。请检查这里Hi@Ravi,是否可以向我发送更多数据。执行时间总是低于1毫秒,我真的看不出某些索引是否工作得更好。你可以把它放在一些存储或直接发送到我的电子邮件配置文件。然后我会将结果发布到这里,创建了更多数据的数据库,正好复制了我现在的数据库。请从这里下载文件。非常感谢你的时间和努力。嗨@Bernd Buffen,真的很棒。出色的表现。但唯一的问题是它在给定的时间间隔内返回最小和最大DClose值。但我需要这个区间的第一个和最后一个值。以AssetId=1为例,在12个月结果集中,第一天的DClose值为42.6500。所以拉夫瓦尔应该是42.6500。但在我们的查询中,它返回38.6900。这是该资产在12个月内的最低价值。与最后一天相同的值为49.4400。但我们的查询返回49.7950作为ralval。这是此间隔中的最大值。请解决这个问题。感谢您的大力帮助。从eod_数据中选择STRAIGHT_JOIN AssetId、AssetName、a.Isin、ed.DDate、ed.DClose ed上的左连接资产a.Isin=a.Isin Internal JOIN AssetClass ac上的ac.AssetClassId=a.AssetClassId内部连接资产组asg上的ASETSUBGroupId=ac.AssetSubGroupId其中ed.DDate>=now()-间隔12个月,DDate ASC的asg.AssetGroupId=1和a.AssetId=1订单;只是为了检查我们结果中的第一个和最后一个值。嗨@Bernd Buffen运气好吗?@Ravi-是的,但我必须考虑一下最佳解决方案。今晚我可以做这件事。所有r[abc]lval值相同是否正确。每次都是范围的第一行和最后一行,但最后一行总是一样的?是的,你是对的。它是该范围的第一个和最后一个值。实际上,有4种不同类型的过滤器,带有日期和间隔。日期可能相同,也可能不同。对于默认视图,我们现在将显示默认间隔。但用户可以随时更改过滤器,并检查结果。那时我们必须得到所有的r[abc]lval。我希望你了解情况。非常感谢。
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;