繁体   English   中英

优化 MySQL 查询以减少运行时间

[英]Optimizing MySQL query to reduced runtime

下面是将在具有 60+ 百万和 400+ 百万条记录的两个表上运行的查询。 只有表名不同,否则两个表的查询相同。

SELECT * FROM 
(
    SELECT A.CUSIP, A.ISIN, A.SEDOL, A.LocalCode, A.MIC, A.ExchgCD, A.PrimaryExchgCD, A.Currency, A.Open, A.High, A.Low, A.Close, A.Mid, A.Ask, A.Last, 
    A.Bid, A.Bidsize, A.Asksize, A.TradedVolume, A.SecID, A.PriceDate, A.MktCloseDate, A.VolFlag, A.IssuerName, A.TotalTrades, A.CloseType, A.SectyCD,
    row_number() OVER (partition by A.CUSIP order by A.MktCloseDate desc) as 'rank'
    from EDI_Price04 A 
    WHERE A.CUSIP IN (
    "91879Q109", "583840509", "583840608", "59001A102", "552848103") AND (A.PrimaryExchgCD = A.ExchgCD) AND A.CloseType='CC'
) t WHERE t.rank <= 3; 

A.CUSIP IN ()条件有 10-15 个值时,查询在 2-3 秒内完成。 使用 400 个值需要 28 秒。 但我想让A.CUSIP IN ()一次取 2k-3k 值。 这是我的表结构。

CREATE TABLE `EDI_Price04` (
  `MIC` varchar(6) NOT NULL DEFAULT '',
  `LocalCode` varchar(60) NOT NULL DEFAULT '' COMMENT 'PricefileSymbol',
  `ISIN` varchar(12) DEFAULT NULL,
  `Currency` varchar(3) NOT NULL DEFAULT '',
  `PriceDate` date DEFAULT NULL,
  `Open` double DEFAULT NULL,
  `High` double DEFAULT NULL,
  `Low` double DEFAULT NULL,
  `Close` double DEFAULT NULL,
  `Mid` double DEFAULT NULL,
  `Ask` double DEFAULT NULL,
  `Last` double DEFAULT NULL,
  `Bid` double DEFAULT NULL,
  `BidSize` int(11) DEFAULT NULL,
  `AskSize` int(11) DEFAULT NULL,
  `TradedVolume` bigint(20) DEFAULT NULL,
  `SecID` int(11) NOT NULL DEFAULT '0',
  `MktCloseDate` date NOT NULL DEFAULT '0000-00-00',
  `Volflag` char(1) DEFAULT NULL,
  `IssuerName` varchar(255) DEFAULT NULL,
  `SectyCD` varchar(3) DEFAULT NULL,
  `SecurityDesc` varchar(255) DEFAULT NULL,
  `SEDOL` varchar(7) DEFAULT NULL,
  `CUSIP` varchar(9) DEFAULT NULL COMMENT 'USCode',
  `PrimaryExchgCD` varchar(6) DEFAULT NULL,
  `ExchgCD` varchar(6) NOT NULL DEFAULT '',
  `TradedValue` double DEFAULT NULL,
  `TotalTrades` int(11) DEFAULT NULL,
  `Comment` varchar(255) DEFAULT NULL,
  `Repush` tinyint(4) NOT NULL DEFAULT '0',
  `CloseType` varchar(2) NOT NULL DEFAULT '',
  PRIMARY KEY (`MIC`,`LocalCode`,`Currency`,`SecID`,`MktCloseDate`,`ExchgCD`,`Repush`,`CloseType`),
  KEY `idx_EDI_Price04_0` (`MIC`),
  KEY `idx_EDI_Price04_1` (`LocalCode`),
  KEY `idx_EDI_Price04_2` (`ISIN`),
  KEY `idx_EDI_Price04_3` (`PriceDate`),
  KEY `idx_EDI_Price04_4` (`SEDOL`),
  KEY `idx_EDI_Price04_5` (`CUSIP`),
  KEY `idx_EDI_Price04_6` (`PrimaryExchgCD`),
  KEY `idx_EDI_Price04_7` (`ExchgCD`),
  KEY `idx_EDI_Price04_8` (`CloseType`),
  KEY `idx_EDI_Price04_9` (`MktCloseDate`),
  KEY `idx_EDI_Price04_CUSIP_ExchgCD_CloseType_MktCloseDate` (`CUSIP`,`ExchgCD`,`CloseType`,`MktCloseDate`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

对于此查询:

SELECT *
FROM (SELECT a.* 
             ROW_NUMBER() OVER (PARTITION BY A.CUSIP ORDER BY A.MktCloseDate DESC) as rank
      FROM EDI_Price04 A 
      WHERE A.CUSIP IN ('91879Q109', '583840509', '583840608', '59001A102', '552848103') AND
            A.PrimaryExchgCD = A.ExchgCD AND
            A.CloseType = 'CC'
     ) t
WHERE t.rank <= 3; 

开始的地方是索引。 对于此查询,您需要EDI_Price04(CloseType, CUSIP, ExchgCD, MktCloseDate)上的索引。

不幸的是,条件A.PrimaryExchgCD = A.ExchgCD阻止了索引查找。 如果您要更改查询/数据,那么一种方法是在它们相同时添加一个标志,而不是单独查看这些值。 这将允许索引:

EDI_Price04(CloseType, IsPrimary, CUSIP, PrimaryExchgCD, ExchgCD, MktCloseDate)
  PRIMARY KEY (id),
  UNIQUE(`MIC`,`LocalCode`,`Currency`,`SecID`,`MktCloseDate`,
         `ExchgCD`,`Repush`,`CloseType`),
  -- KEY `idx_EDI_Price04_0` (`MIC`),
  KEY `idx_EDI_Price04_1` (`LocalCode`),
  KEY `idx_EDI_Price04_2` (`ISIN`),
  KEY `idx_EDI_Price04_3` (`PriceDate`),
  KEY `idx_EDI_Price04_4` (`SEDOL`),
  -- KEY `idx_EDI_Price04_5` (`CUSIP`),
  KEY `idx_EDI_Price04_6` (`PrimaryExchgCD`),
  KEY `idx_EDI_Price04_7` (`ExchgCD`),
  KEY `idx_EDI_Price04_8` (`CloseType`),
  KEY `idx_EDI_Price04_9` (`MktCloseDate`),
  KEY `idx_EDI_Price04_CUSIP_ExchgCD_CloseType_MktCloseDate` (`CUSIP`,
                          `ExchgCD`, `CloseType`, `MktCloseDate`)
  KEY (CUSIP, MktCloseDate)

PK 中有这么多列会占用空间和插入时间。 所以,我添加了一个id ,它需要是AUTO_INCREMENT

键 0 和 5 是多余的,因为规则“如果您有INDEX(a,b) ,则INDEX(a)多余的。

我添加了(CUSIP, MktCloseDate)希望它能优化 RANK 表达式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM