纯数字字符串模糊搜索问题

XphteR 2016-02-21 08:49:05
加精
情况是这样的:有个表存放的是400电话号码数据,400电话号码字段是nvarchar类型,数据类似于4000377888这样的。
如何能以比较快的速度查询出包含某数字序列的号码呢?
比如:查询所有包含0377的号码。
方法1:SELECT * FROM tableName WHERE Number400 LIKE '%0377%'
存在的问题:无法使用索引,速度太慢;

方法2:SELECT * FROM tableName WHERE CONTAINS(Number400, '0377')
存在的问题:即使将非索引字表关闭,也依然查询不到任何数据,似乎MSSQL始终认为数字是干扰词;

谢谢
...全文
4089 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
mingqing6364 2016-03-19
  • 打赏
  • 举报
回复
最后总结一下: 1.如果一个字段的不同取值数量很少(比如10个)那就没必要去给它加索引 2.UPDATE写的太复杂(各种函数表达式)会严重拖累性能 3.insert into tablename values (),() 这种复合插入(最多接1000个)真心很快
mingqing6364 2016-03-19
  • 打赏
  • 举报
回复
@XphteR SQL是结构化查询语言,结构化越彻底,查询速度越快,下面我会用SQL代码给出一个优化方案
先说下效果:
优化前出结果要5秒左右,优化后在2秒内

第一步当然是创建表了:
CREATE TABLE [dbo].[PN]
(
[PhoneNum] nvarchar(10),
[Num_Count_0] tinyint,
[Num_Count_1] tinyint,
[Num_Count_2] tinyint,
[Num_Count_3] tinyint,
[Num_Count_4] tinyint,
[Num_Count_5] tinyint,
[Num_Count_6] tinyint,
[Num_Count_7] tinyint,
[Num_Count_8] tinyint,
[Num_Count_9] tinyint
);
/*
受影响的行: 0
时间: 0.002s
*/

第二步,插入数据,PS:这一步的SQL我省略了一大段,要不然太长了,我是直接用EXCEL拖出来的^_^

DECLARE @i BIGINT = 4000377888
WHILE @i <= 4005177888
BEGIN
INSERT INTO PN (PhoneNum) VALUES
(CAST(@i AS NVARCHAR(10))),
(CAST(@i+1 AS NVARCHAR(10))),
(CAST(@i+2 AS NVARCHAR(10))),
(CAST(@i+3 AS NVARCHAR(10))),
(CAST(@i+4 AS NVARCHAR(10))),
(CAST(@i+5 AS NVARCHAR(10))),
……
(CAST(@i+997 AS NVARCHAR(10))),
(CAST(@i+998 AS NVARCHAR(10))),
(CAST(@i+999 AS NVARCHAR(10)))
SET @i = @i + 1000
END;
/*
受影响的行: 1000
时间: 13.308s
*/

第三步,UPDATE,这一步平时可以在插入的时候完成

UPDATE PN SET
Num_Count_0 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '0', '')),
Num_Count_1 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '1', '')),
Num_Count_2 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '2', '')),
Num_Count_3 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '3', '')),
Num_Count_4 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '4', '')),
Num_Count_5 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '5', '')),
Num_Count_6 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '6', '')),
Num_Count_7 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '7', '')),
Num_Count_8 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '8', '')),
Num_Count_9 = LEN(PhoneNum) - LEN(REPLACE(PhoneNum, '9', ''))
/*
受影响的行: 4801000
时间: 71.020s
*/

最后,几种查询方案用时比较

PRINT @@version
/*
Microsoft SQL Server 2008 R2 (RTM) - 10.50.1600.1 (Intel X86)
Apr 2 2010 15:53:02
Copyright (c) Microsoft Corporation
Express Edition on Windows NT 5.1 <X86> (Build 2600: Service Pack 3) (Hypervisor)

受影响的行: 0
时间: 0.007s
*/
SELECT PhoneNum FROM PN WHERE PhoneNum LIKE '%0377%'
/*
受影响的行: 0
时间: 5.277s
*/

SELECT SUM(1) FROM PN WHERE PhoneNum LIKE '%0377%'
/*
受影响的行: 0
时间: 4.607s
*/

SELECT PhoneNum FROM PN WHERE Num_Count_0 >= 1 AND Num_Count_3 >= 1 AND Num_Count_7 >= 2 AND PhoneNum LIKE '%0377%'
/*
受影响的行: 0
时间: 1.429s
*/

SELECT SUM(1) FROM PN WHERE Num_Count_0 >= 1 AND Num_Count_3 >= 1 AND Num_Count_7 >= 2 AND PhoneNum LIKE '%0377%'
/*
受影响的行: 0
时间: 0.740s
*/


最后的最后贴出我SQL SERVER服务器的配置,虚拟机,分配了4个CPU核心过去
com8716187161 2016-03-14
  • 打赏
  • 举报
回复
select 1 as id into #tt where '4000377888' LIKE '4000377%' select 1 as id into #tt2 where '4000037788' LIKE '400_0377%' select 1 as id into #tt3 where '4000003778' www.60400.com LIKE '400__0377%' select *From #tt union all select *From #tt2 union all select *From #tt3
我爱娃哈哈 2016-03-03
  • 打赏
  • 举报
回复
引用 17 楼 hemowolf 的回复:
1、把表增加两个字段,一段保存 0377 那部分,一段保存 888 那部分,作为冗余字段,加快查询用的,由于是数字,可以考虑使用 int 型,可以少占点空间 2、在这两个字段上建索引 查询可以变 like 为数值范围 比如查询 0377,可以是: select * from youtable where p1 = 377 -- 400 0377 XXX or (p2 between 700 and 799 and p1 mod 100 = 37) -- 400 X037 7XX or (p2 between 770 and 779 and p1 mod 10 = 3) -- 400 XXX3 77X or (p2 = 337 and p1 mod 10 = 0) -- 400 XXX0 377 between 放前面,取模放后面,应该对效率有提升
好方法
giftsf 2016-03-03
  • 打赏
  • 举报
回复
select 1 as id into #tt where '4000377888' LIKE '4000377%' select 1 as id into #tt2 where '4000037788' LIKE '400_0377%' select 1 as id into #tt3 where '4000003778' LIKE '400__0377%' select *From #tt union all select *From #tt2 union all select *From #tt3 索引就用上了
qzyf1992 2016-03-02
  • 打赏
  • 举报
回复
先 SELECT * FROM tableName WHERE Number400 LIKE '0377%' 没有前置的%索引会使用索引 查找,把找到的结果集放入临时表 然后使用SELECT * FROM tableName WHERE Number400 LIKE '%0377%' 查询临时表
小灰狼 2016-03-01
  • 打赏
  • 举报
回复
1、把表增加两个字段,一段保存 0377 那部分,一段保存 888 那部分,作为冗余字段,加快查询用的,由于是数字,可以考虑使用 int 型,可以少占点空间 2、在这两个字段上建索引 查询可以变 like 为数值范围 比如查询 0377,可以是: select * from youtable where p1 = 377 -- 400 0377 XXX or (p2 between 700 and 799 and p1 mod 100 = 37) -- 400 X037 7XX or (p2 between 770 and 779 and p1 mod 10 = 3) -- 400 XXX3 77X or (p2 = 337 and p1 mod 10 = 0) -- 400 XXX0 377 between 放前面,取模放后面,应该对效率有提升
小灰狼 2016-03-01
  • 打赏
  • 举报
回复
引用 1 楼 fengqingtao2008 的回复:
路过帮顶下,如果是纯数字的话,先把字段值 Cast转换成数字类型,在做进一步的模糊筛选!
这样要做一次全表扫描,还要把每一行的相关字段作转换,速度快不起来,反而会更慢
-0000- 2016-03-01
  • 打赏
  • 举报
回复
400后面每个数字存一列,那不是更快。。。
XphteR 2016-02-29
  • 打赏
  • 举报
回复
引用 7 楼 xiaoxiangqing 的回复:
最好分表来保存,不然速度快不了
测试了3天,480多万数据,不管如何做分区表,速度还是很慢。
XphteR 2016-02-26
  • 打赏
  • 举报
回复
引用 8 楼 SugarToffee 的回复:
你截取字符串吧毕竟=比like快

 SELECT * FROM tableName WHERE substring( Number400,4,4)= 0377
现在是想实现类似LIKE匹配查询的功能,所以没办法用substring函数。
XphteR 2016-02-26
  • 打赏
  • 举报
回复
引用 12 楼 shoppo0505 的回复:
[quote=引用 10 楼 XphteR 的回复:]
[quote=引用 6 楼 shoppo0505 的回复:]
插入index应该比like效率高.
你试一下select Number from....那个快,在建立index,然后include其他字段看看.

你现在的问题感觉是之后select字段时候阻塞了,和你提到的两个函数关系不大

不太明白,能否详细说一下,多谢。[/quote]

你先分别执行下,
1. SELECT Number FROM tableName WHERE Number400 LIKE '%0377%'
2. SELECT Number FROM tableName WHERE CONTAINS(Number400, '0377')
看哪个快,如果一样的话说明导致速度变化的原因是执行select时候的阻塞。

如果上述成立,那你可以对列 Number400建立一个index,里面include进去你想要最后select出来的内容就行[/quote]
试过了,用全文索引查询不出来任何数据

SELECT Number400 FROM tableName WHERE CONTAINS(Number400, '0377')

shoppo0505 2016-02-26
  • 打赏
  • 举报
回复
引用 10 楼 XphteR 的回复:
[quote=引用 6 楼 shoppo0505 的回复:] 插入index应该比like效率高. 你试一下select Number from....那个快,在建立index,然后include其他字段看看. 你现在的问题感觉是之后select字段时候阻塞了,和你提到的两个函数关系不大
不太明白,能否详细说一下,多谢。[/quote] 你先分别执行下, 1. SELECT Number FROM tableName WHERE Number400 LIKE '%0377%' 2. SELECT Number FROM tableName WHERE CONTAINS(Number400, '0377') 看哪个快,如果一样的话说明导致速度变化的原因是执行select时候的阻塞。 如果上述成立,那你可以对列 Number400建立一个index,里面include进去你想要最后select出来的内容就行
顾西昂 2016-02-26
  • 打赏
  • 举报
回复
要不你把要搜的字段全写出来 这样毕竟优化了
XphteR 2016-02-26
  • 打赏
  • 举报
回复
引用 6 楼 shoppo0505 的回复:
插入index应该比like效率高. 你试一下select Number from....那个快,在建立index,然后include其他字段看看. 你现在的问题感觉是之后select字段时候阻塞了,和你提到的两个函数关系不大
不太明白,能否详细说一下,多谢。
顾西昂 2016-02-23
  • 打赏
  • 举报
回复
你截取字符串吧毕竟=比like快

 SELECT * FROM tableName WHERE substring( Number400,4,4)= 0377
xiaoxiangqing 2016-02-23
  • 打赏
  • 举报
回复
最好分表来保存,不然速度快不了
shoppo0505 2016-02-22
  • 打赏
  • 举报
回复
插入index应该比like效率高. 你试一下select Number from....那个快,在建立index,然后include其他字段看看. 你现在的问题感觉是之后select字段时候阻塞了,和你提到的两个函数关系不大
XphteR 2016-02-22
  • 打赏
  • 举报
回复
引用 4 楼 ch21st 的回复:
你有没有试试charindex

SELECT * FROM tableName WHERE CHARINDEX( '0377', Number400)>0
试过了,速度没有直接LIKE快
XphteR 2016-02-22
  • 打赏
  • 举报
回复
引用 1 楼 fengqingtao2008 的回复:
路过帮顶下,如果是纯数字的话,先把字段值 Cast转换成数字类型,在做进一步的模糊筛选!
谢谢帮顶。这个字段是可以存储为整数类型的,数字类型怎么做模糊筛选呢?
加载更多回复(3)
介绍就不多说了,下边是部分目录,觉得有用的话就顶一个C:.│ sqlserver2000.txt│ ├─第01章│ 1.9.1 设置内存选项.sql│ 1.9.2(2) 使用文件及文件组.sql│ 1.9.2(3) 调整tempdb数据库的文件属性.sql│ ├─第02章│ │ 2.1 日期概念理解中的一些测试.sql│ │ 2.2.4 CONVERT在日期转换中的使用示例.sql│ │ 2.3.3 SET DATEFORMAT对日期处理的影响.sql│ │ 2.3.4 SET LANGUAGE对日期处理的影响示例.sql│ │ 2.4.1 日期格式化处理.sql│ │ 2.4.2 日期推算处理.sql│ │ 2.4.3 特殊日期加减函数.sql│ │ 2.5.1 查询指定日期段内过生日的人员.sql│ │ 2.5.2 生成日期列表的函数.sql│ │ 2.5.3 工作日处理函数(标准节假日).sql│ │ 2.5.3 工作日处理函数(自定义节假日).sql│ │ 2.5.4 计算工作时间的函数.sql│ │ │ └─其他│ 交叉表.sql│ 任意两个时间之间的星期几的次数-横.sql│ 任意两个时间之间的星期几的次数-纵.sql│ 复杂年月处理.sql│ 统计--交叉表+日期+优先.sql│ ├─第03章│ │ 3.2 各种字符串分拆处理函数.sql│ │ 3.3 各种字符串合并处理示例.sql│ │ 3.4.1 分段截取函数.sql│ │ 3.4.2 分段更新函数.sql│ │ 3.4.3 IP地址处理函数.sql│ │ 3.5.1 字符串比较函数.sql│ │ 3.5.2 字符串并集&交集处理示例.sql│ │ 3.5.3 字符串分拆并统计的处理示例.sql│ │ 3.5.5 字符串处理示例--列车车次查询.sql│ │ 3.6.2 字符串在编号查询中的应用示例及常见问题.sql│ │ 3.6.3 动态参数的存储过程示例.sql│ │ 3.6.4 动态他Transact-SQL语句处理中的常见问题演示.sql│ │ 3.7.3 text与ntext字段的复制和合并处理示例.sql│ │ 3.7.4 text与image字段转换处理示例.sql│ │ 3.7.5 ntext字段的REPLACE处理示例.sql│ │ │ └─其他│ varbinary转换成字符串.sql│ 关键字搜索.sql│ 分解公式.sql│ 字符串分拆--格式化.sql│ 得到一个字符串在另一个字符串中出现的次数.sql│ 数字转换成十六进制.sql│ 比较第一与第二个字符串,是否有连续的5个字符相同.sql│ 生成查询的模糊匹配字符串.sql│ 简繁转换.sql│ 统计一个表中某个字符出现最多的字母.sql│ 非法字符串处理.sql│ ├─第04章│ │ 4.1.5 在各种处理中应用排序规则的示例.sql│ │ 4.2.1 排序规则在拼音处理中的应用.sql│ │ 4.2.2 排序规则在全角与半角处理中的应用.sql│ │ │ └─其他│ 生成GB2312汉字表.sql│ 生成GBK汉字表.sql│ 自动获取汉字笔画.sql│ ├─第05章│ │ 5.1.1 SET IDENTITY_INSERT 中的几个问题.sql│ │ 5.1.1 修改标识值的示例.sql│ │ 5.1.1 标识列与普通列互相转换的示例.sql│ │ 5.2.1 查表法按日期生成流水号的示例.sql│ │ 5.2.1 查表法生成流水号的示例.sql│ │ 5.2.2 使用编号表按日期生成流水号的示例.sql│ │ 5.2.2 使用编号表生成流水号的示例.sql│ │ 5.2.3 生成字母随机编号的示例(仅大小或者小写).sql│ │ 5.2.3 生成字母随机编号的示例(大小写混合).sql│ │ 5.2.3 生成数字随机编号的示例.sql│ │ 5.3.2 融合了补号处理的编号生成处理示例.sql│ │ 5.3.3 使用UPDATE进行编号重排的处理示例.sql│ │ 5.3.3 使用临时表进行编号重排的处理示例.sql│ │ 5.3.3 使用子查询进行编号重排的处理示例.sql│ │ 5.3.3 名次查询的处理示例.sql│ │ 5.4.1 查询已用编号分布情况的示例(临时表法).sql│ │ 5.4.1 查询已用编号分布情况的示例(子查询法).sql│ │ 5.4.2 查询缺号分布情况的示例.sql│ │ 5.4.3 返回已用编号、缺号分布字符串的处理示例.sql│ │ 5.4.4 缺勤天数统计的处理示例.sql│ │ │ └─其他│ -补位法.sql│ 以另一个表的字段做默认值.sql│ 以另一表的字段生成编号.sql│ 关联部门流水号.sql│ 十六进制.sql│ 学号.sql│ 开票统计--涉及到连号处理.sql│ 新编号查询示例(分类查询).sql│ 新编号查询示例.sql│ 日期流水号.sql│ 材料流水号.sql│ 流水号.sql│ 箱编号连号处理.sql│ 类别自动生成编号示例.sql│ 自已做标识列的例子.sql│ 触发器自动维护已用&未用编号.sql│ 连续编号.sql│ 防止重复的示例.sql│ 项目编号=各项目独立流水号&各年不同.sql│ ├─第06章│ │ 6.1.1 NULL对IN的查询的影响及解决示例.sql│ │ 6.1.2 各种联接的使用示例.sql│ │ 6.1.2 多表联结导致记录重复的示例.sql│ │ 6.1.3 使用UNION实现库存报表的示例.sql│ │ 6.1.5 按指定上下限区间进行数据统计的示例.sql│ │ 6.1.6 随机出题的示例.sql│ │ 6.2.1 ROLLUP实现的分级汇总示例(定义各汇总列标题).sql│ │ 6.2.1 ROLLUP实现的分级汇总示例(带排序及汇总列标题处理).sql│ │ 6.2.1 ROLLUP实现的分级汇总示例(带排序处理).sql│ │ 6.2.1 ROLLUP实现的分级汇总示例.sql│ │ 6.2.1 UNION ALL实现的分级汇总示例.sql│ │ 6.3.1 简单的交叉报表处理示例.sql│ │ 6.3.2 多列转换为行的交叉报表处理示例.sql│ │ 6.3.3 行值动态变化的交叉报表处理示例(转换多列).sql│ │ 6.3.3 行值动态变化的交叉报表处理示例.sql│ │ 6.3.4 化解字符串不能超过8000的方法.sql│ │ 6.3.5 特殊的交叉报表处理示例.sql│ │ 6.4.1 库存明细帐处理示例(包含结存数).sql│ │ 6.4.1 库存明细帐处理示例.sql│ │ 6.4.2 同期及上期数据对比处理示例.sql│ │ 6.4.3 动态分组处理示例.sql│ │ 6.4.4 排行榜处理示例.sql│ │ │ └─其他│ 交叉表--复杂名次.sql│ 交叉表-优先级处理.sql│ 交叉表分析.sql│ 分级汇总.sql│ 分组交叉表.sql│ 列转行.sql│ 固定行列报表.sql│ 复杂交叉表.sql│ 复杂交叉表1.sql│ 多栏显示.sql│ 日期+星期+时间.sql│ 格式化报表.sql│ 横转竖-1.sql│ 横转竖-字段名.sql│ 横转竖-生成字段名.sql│ 横转竖.sql│ 行列互换的复杂交叉表.sql│ 限制列数的交叉表.sql│ ├─第07章│ │ 7.1 splitpage.asp│ │ 7.2.1 TOP n 实现的通用分页存储过程.sql│ │ 7.2.2 字符串缓存实现的通用分页存储过程.sql│ │ 7.2.3 临时表缓存实现的通用分页存储过程.sql│ │ 7.2.4 使用系统存储过程实现的通用分页存储过程.sql│ │ 7.3.1 实现随机分页的通用分页存储过程.sql│ │ 7.3.2 根据分类表实现的分页存储过程.sql│ │ │ └─其他│ sp_cursor.sql│ 基本方法.sql│ ├─第08章│ │ 8.1.2 树形数据分级汇总示例.sql│ │ 8.1.3 树形数据编号重排的通用存储过程.sql│ │ 8.1.3 树形数据编号重排示例.sql│ │ 8.1.4 实现编码规则调整处理的通用存储过程.sql│ │ 8.1.4 生成编码规则调整处理T-SQL语句的函数.sql│ │ 8.1.5 删除节点处理的通用存储过程.sql│ │ 8.1.5 移动节点处理的通用存储过程.sql│ │ 8.2.2 树形数据层次显示处理示例.sql│ │ 8.2.2 树形数据广度排序处理示例.sql│ │ 8.2.2 树形数据深度排序处理示例(模拟单编号法).sql│ │ 8.2.2 树形数据深度排序处理示例(递归法).sql│ │ 8.2.3 查找指定节点的所有子节点的示例函数.sql│ │ 8.2.4 查找指定节点的所有父节点的示例函数.sql│ │ 8.2.5 校验插入指定结点是否导致编码循环的示例函数.sql│ │ 8.2.5 校验表中数据是否有循环编码的通用存储过程.sql│ │ 8.2.6 复制指定节点及其所有子节点到指定结点的处理示例(借鉴方式排序法).sql│ │ 8.2.6 复制指定节点及其所有子节点到指定结点的处理示例.sql│ │ 8.2.7 实现删除指定结点及所有子节点的处理触发器.sql│ │ 8.2.8 逐级汇总示例(循环逐级累计法).sql│ │ 8.2.8 逐级汇总示例(用户定义函数法).sql│ │ 8.3.1 产品配件清单查询示例.sql│ │ 8.3.2 最短乘车路线查询示例.sql│ │ │ └─其他│ xml菜单.sql│ 宝塔形数据的处理-1.sql│ 宝塔形数据的处理.sql│ 树形数据生成xml.sql│ ├─第09章│ │ 9.1.3 访问外部数据源方法总结.sql│ │ 9.5.1 二进制文件存取示例(T-SQL).sql│ │ 9.5.1 二进制文件存取示例(VB&VBA).vbs│ │ a.txt│ │ Schema.ini│ │ │ └─其他│ bcp-数据导入导出(全).sql│ bcp-数据导入导出-二进制文件.sql│ bcp-数据导出为文件.sql│ bcp表数据存为XML.sql│ SQL Server到Oracle连接服务器的实现.sql│ SQL Server到SQLBASE连接服务器的实现.sql│ SQL Server到SYBASE连接服务器的实现.sql│ sql导出mysql.sql│ textcopy实现文件存取.sql│ Vb程序实现文件存取.sql│ 导入文本文件时如何指定字段类型.sql│ 导出northwind中Employees的图像.sql│ 将某个目录上的Excel表,导入到数据库中.sql│ 数据导入导出基本方法.sql│ 用ASP上传&下载文件.sql

27,579

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 应用实例
社区管理员
  • 应用实例社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧