【问题标题】:Speed up MySQL inner join with LIKE clause使用 LIKE 子句加速 MySQL 内部连接
【发布时间】:2018-06-14 22:09:01
【问题描述】:

我有以下 2 个表,api_analytics_data 和 telecordia。

CREATE TABLE `api_analytics_data` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `upload_file_id` bigint(20) NOT NULL,
  `partNumber` varchar(100) DEFAULT NULL,
  `clei` varchar(45) DEFAULT NULL,
  `description` varchar(150) DEFAULT NULL,
  `processed` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `idx_aad_clei` (`clei`),
  KEY `idx_aad_pn` (`partNumber`),
  KEY `id_aad_processed` (`processed`),
  KEY `idx_combo1` (`partNumber`,`clei`,`upload_file_id`)
) ENGINE=InnoDB CHARSET=latin1;

CREATE TABLE `telecordia` (
  `tid` int(11) NOT NULL AUTO_INCREMENT,
  `ProdID` varchar(50) DEFAULT NULL,
  `Mfg` varchar(20) DEFAULT NULL,
  `Pn` varchar(50) DEFAULT NULL,
  `Clei` varchar(50) DEFAULT NULL,
  `Series` varchar(50) DEFAULT NULL,
  `Dsc` varchar(50) DEFAULT NULL,
  `Eci` varchar(50) DEFAULT NULL,
  `AddDate` date DEFAULT NULL,
  `ChangeDate` date DEFAULT NULL,
  `Cost` float DEFAULT NULL,
  PRIMARY KEY (`tid`),
  KEY `telecordia.ProdID` (`ProdID`) USING BTREE,
  KEY `telecordia.clei` (`Clei`),
  KEY `telecordia.pn` (`Pn`),
  KEY `telcordia.eci` (`Eci`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

用户通过 Web 界面使用 Excel/CSV 文件将数据上传到 api_analytics_data。数据包含 partNumbers 或 CLEI。然后我通过加入 telecordia 表来更新 api_analytics_data 表。 telecordia 表是 partNumber 和 Cleis 的主列表。

所以如果用户上传一个 CLEI 文件,我使用的更新/加入是:

update api_analytics_data aad
  inner join telecordia t on aad.clei = t.Clei
  set aad.partNumber = t.Pn
  where aad.partNumber is null
  and aad.upload_file_id = 5;

它工作得很快,但不是很彻底。我遇到的问题是上传的 CLEI 可能只是 Telecordia 表中 CLEI 的子字符串。

例如,上传的 CLEI 可能是“5SC1DX0”。在telcordia表中,正确匹配的行是:

tid:        184324    
ProdID:     472467  
Mfg:        PLSE 
Pn:         AUA58-2-REV-E            
Clei:       5SC1DX04AA        
Series:     null
Dsc:        DL SGL-PTY POTS CU RT                
Eci:        205756    
AddDate:    1994-03-18      
ChangeDate: 1998-04-13     
Cost:       null

所以显然我的更新在这种情况下不起作用,即使 5SC1DX05SC1DX04AA 是同一部分。

我需要的是通配符搜索。但是,当我尝试这个时,它非常慢。大约 4500 行上传到 api_analytics_data 表中,它运行了大约 10 分钟,然后失去了与服务器的连接。

update api_analytics_data aad
  inner join telecordia t on aad.clei like concat(t.Clei,'%')
  set aad.partNumber = t.Pn
  where aad.partNumber is null 
  and aad.upload_file_id = 5;

有没有办法优化它以使其快速运行?

【问题讨论】:

  • 确保以下有索引:aad.clei、t.Clei、aad.partNumber、aad.upload_file_id
  • 如果您使用的是 MySQL 5.6 及更高版本,您可以使用在创建时为表/列启用的全文搜索功能或更改表以启用它。您可以找到有关它的更多详细信息here
  • idx_aad_pn - 这个索引是多余的

标签: php mysql sql sql-update inner-join


【解决方案1】:

正确答案是“不”。更好的做法是在telecordia 中创建一个新列,其中包含正确 Clei 值,可用于连接表。在最新版本的 MySQL 中,这甚至可以是计算列并被索引。

也就是说,如果匹配部分的长度始终相同,您也许可以做一些事情。如果是这样,试试这个:

update api_analytics_data aad inner join
       telecordia t
       on t.Clei = left(aad.clei, 7)
  set aad.partNumber = t.Pn
  where aad.partNumber is null and aad.upload_file_id = 5;

对于此查询,您需要在 api_analytics_data(upload_fiel_id, partNumber, clei)telecordia(clei, pn) 上建立索引。

【讨论】:

  • 很遗憾,没有“正确”的 CLEI。这些零件标识符都是不同的长度,由不同的代码组成。所以对于 CLEI 'SP3QAF0BAA',SP 是家族代码,3Q 是子家族代码,AF0 是特征代码,B 是参考代码,AA 是互补代码。所以SP3QA、SP3QAF、SP3QAF0、SP3QAF0B等都是同一个部分。
  • @scott80109 。 . .听起来你需要一个参考表给我。
猜你喜欢
  • 2011-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-09
  • 1970-01-01
  • 1970-01-01
  • 2011-04-01
相关资源
最近更新 更多