Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用replace在MySQL中更快地匹配字符串_Mysql_Sql_Where Clause - Fatal编程技术网

使用replace在MySQL中更快地匹配字符串

使用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

我在尝试从一个表中选择行时遇到了一个有趣的问题,在我的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` 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等。我们的搜索需要返回所有这些零件。