【问题标题】:MySQL performance issue on multiple select inside each otherMySQL相互内部多选的性能问题
【发布时间】:2020-10-03 09:24:23
【问题描述】:

如果您认为有 200,000 个数据很大,但加载时间超过 10 秒,您可以在下面看到我的查询是一个在大表上运行的大查询。我希望获得专家帮助以优化查询:任何建议都将受到高度赞赏。

SELECT    mt5_users.Name       AS Name, 
      Test2.Login AS SLogin, 
      ( 
             SELECT COUNT(Test.Order) 
             FROM   ( 
                           SELECT * 
                           FROM   ( 
                                           SELECT   MAX(`Order`)                                                                                 AS `Order`,
                                                    SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT Time SEPARATOR ","), ",", 1), ",", -1) AS OPEN_TIME,
                                                    SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT Time SEPARATOR ","), ",", 2), ",", -1) AS CLOSE_TIME,
                                                    MAX(Profit)                                                                                  AS Profit,
                                                    MAX(Storage)                                                                                 AS Storage,
                                                    MAX(Login)                                                                                   AS Login,
                                                    MAX(Action)                                                                                  AS Action,
                                                    MAX(Entry)                                                                                   AS Entry
                                           FROM     `mt5_deals_2020` 
                                           WHERE    Time BETWEEN "2020-09-01" AND      "2020-10-01" 
                                           AND      Entry IN ("0", 
                                                              "1") 
                                           GROUP BY PositionID) AS Main 
                           WHERE  OPEN_TIME != CLOSE_TIME) As Test
             WHERE  Login = SLogin 
             AND    Test.Entry <> "0" 
             AND    Test.CLOSE_TIME BETWEEN "2020-09-01" AND    "2020-10-01" 
             AND    TIMESTAMPDIFF(MINUTE,Test.OPEN_TIME,Test.CLOSE_TIME) <= "5"
             AND    Test.Action <= 1 )        AS Scalp, 
      SUM(Test2.Profit+Test2.Storage) AS Profit, 
      ( 
             SELECT COUNT(mt5_deals_2020.order) 
             FROM   mt5_deals_2020 
             WHERE  Login = SLogin 
             AND    mt5_deals_2020.Time BETWEEN "2020-09-01" AND    "2020-10-01" 
             AND    mt5_deals_2020.Action <= 1 
             AND    mt5_deals_2020.Entry <> "0" ) AS Trades, 
      ( 
             SELECT SUM(mt5_deals_2020.Profit+mt5_deals_2020.Storage) 
             FROM   mt5_deals_2020 
             WHERE  Login = SLogin 
             AND    mt5_deals_2020.Time BETWEEN "2020-09-01" AND    "2020-10-01" 
             AND    mt5_deals_2020.Entry <> "0" 
             AND    mt5_deals_2020.Action <= 1 ) AS PL 
FROM      ( 
                 SELECT * 
                 FROM   ( 
                                 SELECT   MAX(`Order`)                                                                                 AS `Order`,
                                          SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT Time SEPARATOR ","), ",", 1), ",", -1) AS OPEN_TIME,
                                          SUBSTRING_INDEX(SUBSTRING_INDEX(GROUP_CONCAT(DISTINCT Time SEPARATOR ","), ",", 2), ",", -1) AS CLOSE_TIME,
                                          MAX(Profit)                                                                                  AS Profit,
                                          MAX(Storage)                                                                                 AS Storage,
                                          MAX(Login)                                                                                   AS Login,
                                          MAX(Action)                                                                                  AS Action,
                                          MAX(Entry)                                                                                   AS Entry
                                 FROM     `mt5_deals_2020` 
                                 WHERE    Time BETWEEN "2020-09-01" AND      "2020-10-01" 
                                 AND      Entry IN ("0", 
                                                    "1") 
                                 GROUP BY PositionID) AS Main1
                 WHERE  OPEN_TIME != CLOSE_TIME) As Test2
LEFT JOIN mt5_users 
ON        Test2.Login = mt5_users.Login 
WHERE     mt5_users.Group IN ("KUVVARSTUSD", 
                              "real\\KUV3VARSIUSD", 
                              "real\\KUVVARPLUSD", 
                              "real\\KUVVARGOUSD", 
                              "real\\KUVVARGOEUR" 
                              ) 
AND       Test2.CLOSE_TIME BETWEEN "2020-09-01" AND       "2020-10-01" 
AND       TIMESTAMPDIFF(MINUTE,Test2.OPEN_TIME,Test2.CLOSE_TIME) <= "5" 
AND       Test2.Action <= 1 
GROUP BY  Test2.Login

我需要开仓单和平仓单的时间差和其他一些数据等等里面选择我做的就是这样。

解释结果添加:

【问题讨论】:

  • 您可以在您的问题中添加EXPLAIN PLAN 之类的信息吗? (更多信息:SO
  • 查询的目的是什么?对逻辑的解释以及示例数据和结果在这里会有所帮助。

标签: mysql optimization


【解决方案1】:

首先,让我们简化

        SELECT  COUNT(Test.Order)
            FROM  
            (
                SELECT  *
                    FROM  
                    (
                        SELECT  ...
                            FROM  `mt5_deals_2020`
                            WHERE  Time BETWEEN "2020-09-01" AND "2020-10-01"
                              AND  Entry IN ("0", "1")
                            GROUP BY  PositionID
                    ) AS Main
                    WHERE  OPEN_TIME != CLOSE_TIME
            ) As Test
            WHERE  Login = SLogin
              AND  Test.Entry <> "0"
              AND  ...

        SELECT  COUNT(*)
                    FROM  
                    (
                        SELECT  ...
                            FROM  `mt5_deals_2020`
                            WHERE  Time BETWEEN "2020-09-01" AND "2020-10-01"
                              AND  Entry IN ("0", "1")
                            GROUP BY  PositionID
                    ) AS Main
                    WHERE  OPEN_TIME != CLOSE_TIME
                    HAVING  Login = SLogin
                       AND  Test.Entry <> "0"
                       AND  ...

注意事项:

  • COUNT(x) 测试 x 是否为 NOT NULL;我怀疑这无关紧要。
  • HAVING 类似于 WHERE,但它可以引用表达式,例如 SUM() 之类的聚合。
  • 您的公式有一个SELECT *,它涉及创建一个包含所有“列”的大(?)临时表。我的避免了这种情况。

SUBSTRING_INDEX 很乱。考虑重新设计架构,以便您不需要使用它。

EntryAction 的可能值是多少?可能有更好的方法来对这些进行测试。比如Entry只能是0或者1,最好是mt5_deals_2020.Entry = 1,这样就为索引打开了大门。

潜在错误:

Time BETWEEN "2020-09-01" AND "2020-10-01"

如果 TimeDATE,则包括 10 月 1 日。 (请提供SHOW CREATE TABLE。)我更喜欢以下:

    Time >= "2020-09-01"
AND Time  < "2020-09-01" + INTERVAL 1 MONTH

mt5_users 可能会受益于这种复合、覆盖、索引:

INDEX(Login, Group, Name)   -- in this order

完成其中一些之后,如果您愿意,可以回来进行更多讨论。

【讨论】:

    猜你喜欢
    • 2010-09-25
    • 1970-01-01
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 2016-09-05
    • 1970-01-01
    • 1970-01-01
    • 2016-02-21
    相关资源
    最近更新 更多