使用replace在MySQL中更快地匹配字符串
我在尝试从一个表中选择行时遇到了一个有趣的问题,在我的where子句中,VARCHAR列有多种可能 这是我的表格,大约有700万行:使用replace在MySQL中更快地匹配字符串,mysql,sql,where-clause,Mysql,Sql,Where Clause,我在尝试从一个表中选择行时遇到了一个有趣的问题,在我的where子句中,VARCHAR列有多种可能 这是我的表格,大约有700万行: CREATE TABLE `search_upload_detailed_results` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `surId` bigint(20) DEFAULT NULL, `company` varchar(100) DEFAULT NULL, `country` varcha
CREATE TABLE `search_upload_detailed_results` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`surId` bigint(20) DEFAULT NULL,
`company` varchar(100) DEFAULT NULL,
`country` varchar(45) DEFAULT NULL,
`clei` varchar(100) DEFAULT NULL,
`partNumber` varchar(100) DEFAULT NULL,
`mfg` varchar(100) DEFAULT NULL,
`cond` varchar(45) DEFAULT NULL,
`price` float DEFAULT NULL,
`qty` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`description` varchar(500) DEFAULT NULL,
`status` varchar(45) DEFAULT NULL,
`fileId` bigint(20) DEFAULT NULL,
`nmId` bigint(20) DEFAULT NULL,
`quoteRequested` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `sudr.surId` (`surId`),
KEY `surd.clei` (`clei`),
KEY `surd.pn` (`partNumber`),
KEY `surd.fileId` (`fileId`),
KEY `surd.price` (`price`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
我正在尝试匹配零件号列。问题在于零件号的格式不同,可以在搜索表单中以多种格式输入
示例:零件号“300-1231-932”可以是:
300-1231-932
3001231932
300 1231 932
像这样简单的选择需要0.0008秒
select avg(price) as price from search_upload_detailed_results where
partNumber LIKE '3001231932%' and price > 0;
但它并没有给我所有我需要的匹配。所以我写了这个查询
select avg(price) as price from search_upload_detailed_results
where REPLACE(REPLACE(partNumber,'-',''),' ','') LIKE REPLACE(REPLACE('3001231932%','-',''),' ','') and price > 0;
这给了我所有正确的匹配,但在3.3秒时速度非常慢
select avg(price) as price from search_upload_detailed_results where
partNumber LIKE '3001231932%' and price > 0;
我玩了一些东西,试图减少我正在替换的行数,并想出了这个
select avg(price) as price from search_upload_detailed_results
where price > 0 AND
partNumber LIKE('300%') AND
REPLACE(REPLACE(partNumber,'-',''),' ','') LIKE REPLACE(REPLACE('3001231932%','-',''),' ','');
执行需要0.4秒。相当快,但在多部分搜索中可能仍有点耗时
我想快一点,但这是我能做到的。还有其他方法可以优化此查询吗
更新以显示第三个查询的解释:
# id, select_type, table, type, possible_keys, key, key_len, ref, rows, Extra
1, SIMPLE, search_upload_detailed_results, range, surd.pn,surd.price, surd.pn, 103, , 89670, Using where
显而易见的解决方案是只存储零件号,而不在表中添加额外字符。然后从用户输入中删除这些字符,只需执行一个简单的WHERE partnumber=@input查询 如果不可能,可以将其添加为附加列。在MySQL 5.7中,您可以使用;在早期版本中,可以使用填充此列的触发器 我想快一点,但这是我能做到的。还有其他方法可以优化此查询吗 正如巴尔马所说,如果你真的需要速度,最好的解决方案是3.3秒慢?就是要有一个列,其中包含未转换的数据,希望现在已经标准化,这将允许您在不指定所有不同类型的零件号的情况下查询它 示例:零件号“300-1231-932”可以是: 300-1231-932|| 3001231932 || 300 1231932 我认为您应该担心数据的表示,拥有所有这些不同的“格式”将使其变得困难-您能在数据到达数据库之前将其格式化为一个标准吗 这是我的表格,大约有700万行:
CREATE TABLE `search_upload_detailed_results` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`surId` bigint(20) DEFAULT NULL,
`company` varchar(100) DEFAULT NULL,
`country` varchar(45) DEFAULT NULL,
`clei` varchar(100) DEFAULT NULL,
`partNumber` varchar(100) DEFAULT NULL,
`mfg` varchar(100) DEFAULT NULL,
`cond` varchar(45) DEFAULT NULL,
`price` float DEFAULT NULL,
`qty` int(11) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`description` varchar(500) DEFAULT NULL,
`status` varchar(45) DEFAULT NULL,
`fileId` bigint(20) DEFAULT NULL,
`nmId` bigint(20) DEFAULT NULL,
`quoteRequested` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `sudr.surId` (`surId`),
KEY `surd.clei` (`clei`),
KEY `surd.pn` (`partNumber`),
KEY `surd.fileId` (`fileId`),
KEY `surd.price` (`price`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
别忘了你的索引 如其他地方所述,问题在于表格格式。如果这是不可协商的,那么另一种选择是: 如果有一些格式,但不是太多,并且它们是众所周知的,例如您展示的三种格式,那么可以通过显式地预先计算所有格式并搜索其中任何一种格式,使查询运行得更快
select avg(price) as price from search_upload_detailed_results where
partNumber IN ('300-1231-932', '3001231932', '300 1231 932')
这将最大限度地利用partNumber上的索引。您可能会发现MySQL可以很好地利用精心选择的正则表达式的索引 从搜索\上传\详细\结果中选择avgprice作为价格,其中
零件号REGEXP“^300[-]?1231[-]?932” 为什么不规范化表中的零件号,使其始终采用相同的格式?为什么不更新此列并避免将来出现问题?能否解释一下上一个查询,即执行该查询需要0.4秒。@RaymondNijland,这几乎没有必要。很明显,比较两个计算值的查询不能使用索引。@RaymondNijland抱歉,我没有注意到查询的这一部分。解释表明它使用的是pn键,我猜前缀有很多匹配项,所以速度很慢。是的,这是显而易见的答案,但重构代码和包含partNumber的所有表需要很多时间。我将研究生成专栏的可能性。不幸的是,重新设计这个非常大的应用程序目前还不可能。您的另一个解决方案也不会起作用,因为零件号不会就此停止。同一零件有许多不同版本,如300-1231-932-REV1、300-1231-932-REV2、300-1231-932-LN等。我们的搜索需要返回所有这些零件。