【Oracle】SQL对某字段模糊查询,哪种方案最快?
问题:有一张表hy_test,查找其字段name中包含ufo的记录数,下面哪种方案最快?
A.select count(*) from hy_test where name like '%ufo%'
B.select count(*) from hy_test where instr(name,'ufo')> 0
C.with temp as (select rowid from hy_test t where t.name like '%ufo%')
select count(*) from hy_test where rowid in (select rowid from temp)
D.with temp as (select rowid from hy_test t where t.name like '%ufo%')
select count(*) from hy_test a where exists (select rowid from temp where a.rowid=rowid)
A是常规方案,B是网文推荐的方案,C D 是不常见但也有人推荐的方案。
你心中的答案是哪个?
我先给name加上了索引
create index hy_test_name on hy_test(name);
然后看各自的解释计划:
select count(*) from hy_test where name like '%ufo%'
Plan hash value: 2970624229 --------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 3067 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 62 | | |
|* 2 | INDEX FAST FULL SCAN| HY_TEST_NAME | 7426 | 449K| 3067 (1)| 00:00:01 |
-------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("NAME" LIKE U'%ufo%') Note
-----
- dynamic statistics used: dynamic sampling (level=2) select count(*) from hy_test where instr(name,'ufo')> 0
Plan hash value: 2970624229 --------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 3070 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 62 | | |
|* 2 | INDEX FAST FULL SCAN| HY_TEST_NAME | 7426 | 449K| 3070 (1)| 00:00:01 |
-------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter(INSTR("NAME",U'ufo')>0) Note
-----
- dynamic statistics used: dynamic sampling (level=2) with temp as (select rowid from hy_test t where t.name like '%ufo%')
select count(*) from hy_test where rowid in (select rowid from temp)
Plan hash value: 2970624229 --------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 3067 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 62 | | |
|* 2 | INDEX FAST FULL SCAN| HY_TEST_NAME | 7426 | 449K| 3067 (1)| 00:00:01 |
-------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("HY_TEST"."NAME" LIKE U'%ufo%') Note
-----
- dynamic statistics used: dynamic sampling (level=2) with temp as (select rowid from hy_test t where t.name like '%ufo%')
select count(*) from hy_test a where exists (select rowid from temp where a.rowid=rowid)
Plan hash value: 2970624229 --------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 3067 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 62 | | |
|* 2 | INDEX FAST FULL SCAN| HY_TEST_NAME | 7426 | 449K| 3067 (1)| 00:00:01 |
-------------------------------------------------------------------------------------- Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("A"."NAME" LIKE U'%ufo%') Note
-----
- dynamic statistics used: dynamic sampling (level=2)
至少从解释计划来看,四种方案都是差不多的,Cost 都在3067左右,细究的话。instr方案还稍慢点,到了3070!
drop index hy_test_name
再把索引去掉比较:
无索引
select count(*) from hy_test where name like '%ufo%'
Plan hash value: 1972112514 ------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 3857 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 62 | | |
|* 2 | TABLE ACCESS FULL| HY_TEST | 7426 | 449K| 3857 (1)| 00:00:01 |
------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("NAME" LIKE U'%ufo%') Note
-----
- dynamic statistics used: dynamic sampling (level=2) select count(*) from hy_test where instr(name,'ufo')> 0
Plan hash value: 1972112514 ------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 3860 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 62 | | |
|* 2 | TABLE ACCESS FULL| HY_TEST | 7426 | 449K| 3860 (1)| 00:00:01 |
------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter(INSTR("NAME",U'ufo')>0) Note
-----
- dynamic statistics used: dynamic sampling (level=2) EXPLAIN PLAN FOR
with temp as (select rowid from hy_test t where t.name like '%ufo%')
select count(*) from hy_test where rowid in (select rowid from temp)
Plan hash value: 1972112514 ------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 3857 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 62 | | |
|* 2 | TABLE ACCESS FULL| HY_TEST | 7426 | 449K| 3857 (1)| 00:00:01 |
------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("HY_TEST"."NAME" LIKE U'%ufo%') Note
-----
- dynamic statistics used: dynamic sampling (level=2) EXPLAIN PLAN FOR
with temp as (select rowid from hy_test t where t.name like '%ufo%')
select count(*) from hy_test a where exists (select rowid from temp where a.rowid=rowid)
Plan hash value: 1972112514 ------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 62 | 3857 (1)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 62 | | |
|* 2 | TABLE ACCESS FULL| HY_TEST | 7426 | 449K| 3857 (1)| 00:00:01 |
------------------------------------------------------------------------------ Predicate Information (identified by operation id):
--------------------------------------------------- 2 - filter("A"."NAME" LIKE U'%ufo%') Note
-----
- dynamic statistics used: dynamic sampling (level=2)
现在看,instr仍然是最慢的,cost为3860,其它三个都在3857!
结论:大体上四种方案都没什么差别,细究下,网红方案instr反而是最慢的,看上去最low的%ufo%并不慢。
对此,你能同意吗?面试时遇到这题你会怎么写?
如果你想重复我的实验,可以用以下SQL创建表和数据:
CREATE TABLE hy_test
(
id NUMBER not null primary key,
name NVARCHAR2(60) not null,
score NUMBER(4,0) NOT NULL,
createtime TIMESTAMP (6) not null
) Insert into hy_test
select rownum,dbms_random.string('*',dbms_random.value(6,20)),dbms_random.value(0,20),sysdate from dual
connect by level<=2000000
order by dbms_random.random
然后用一下Java程序改写数据:
package recordchanger; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet; public class RecordChanger {
public boolean changeOnePencent(String table) {
Connection conn = null;
Statement stmt = null; try{
Class.forName(DBParam.Driver).newInstance();
conn = DriverManager.getConnection(DBParam.DbUrl, DBParam.User, DBParam.Pswd);
stmt = conn.createStatement(); long startMs = System.currentTimeMillis(); int totalCount=fetchExistCount(table,stmt);
System.out.println("There are "+toEastNumFormat(totalCount)+" records in the table:'"+table+"'."); int changeCount=totalCount/100;
System.out.println("There are "+toEastNumFormat(changeCount)+" records should be changed."); Set<Integer> idSet=fetchIdSet(totalCount,changeCount,table,stmt);
System.out.println("There are "+toEastNumFormat(idSet.size())+" records in idSet."); int changed=updateRecords(idSet,table,stmt);
System.out.println("There are "+toEastNumFormat(changed)+" records have been changed."); long endMs = System.currentTimeMillis();
System.out.println("It takes "+ms2DHMS(startMs,endMs)+" to update 1% records of table:'"+table+"'.");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
stmt.close();
conn.close();
} catch (SQLException e) {
System.out.print("Can't close stmt/conn because of " + e.getMessage());
}
} return false;
} private int updateRecords(Set<Integer> idSet,String tableName,Statement stmt) throws SQLException{
int updated=0; for(int id:idSet) {
String sql="update "+tableName+" set name='"+getRNDName()+"' where id='"+id+"' ";
updated+= stmt.executeUpdate(sql);
} return updated;
} private String getRNDName() {
String[] arr= {"Andy","Bill","Cindy","ufo","sufo","ufoa","ufot","AufoT","BufoT","1ufoufo","钱八","岳飞","关羽","刘备","曹操","张辽","虚竹","王语嫣"};
int index=getRandom(0,arr.length);
return arr[index];
} // fetch a set of id which should be changed
private Set<Integer> fetchIdSet(int totalCount,int changeCount,String tableName,Statement stmt) throws SQLException{
Set<Integer> idSet=new TreeSet<Integer>(); while(idSet.size()<changeCount) {
int id=getRandom(0,totalCount);
if(idSet.contains(id)==false && isIdExist(id,tableName,stmt)) {
idSet.add(id);
}
} return idSet;
} private boolean isIdExist(int id,String tableName,Statement stmt) throws SQLException{
String sql="select count(*) as cnt from "+tableName+" where id='"+id+"' "; ResultSet rs = stmt.executeQuery(sql); while (rs.next()) {
int cnt = rs.getInt("cnt");
return cnt==1;
} rs.close();
return false;
} // get a random num between min and max
private static int getRandom(int min, int max){
Random random = new Random();
int s = random.nextInt(max) % (max - min + 1) + min;
return s;
} // fetch exist record count of a table
private int fetchExistCount(String tableName,Statement stmt) throws SQLException{
String sql="select count(*) as cnt from "+tableName+""; ResultSet rs = stmt.executeQuery(sql); while (rs.next()) {
int cnt = rs.getInt("cnt");
return cnt;
} rs.close();
return 0;
} // 将整数在万分位以逗号分隔表示
public static String toEastNumFormat(long number) {
DecimalFormat df = new DecimalFormat("#,####");
return df.format(number);
} // change seconds to DayHourMinuteSecond format
private static String ms2DHMS(long startMs, long endMs) {
String retval = null;
long secondCount = (endMs - startMs) / 1000;
String ms = (endMs - startMs) % 1000 + "ms"; long days = secondCount / (60 * 60 * 24);
long hours = (secondCount % (60 * 60 * 24)) / (60 * 60);
long minutes = (secondCount % (60 * 60)) / 60;
long seconds = secondCount % 60; if (days > 0) {
retval = days + "d" + hours + "h" + minutes + "m" + seconds + "s";
} else if (hours > 0) {
retval = hours + "h" + minutes + "m" + seconds + "s";
} else if (minutes > 0) {
retval = minutes + "m" + seconds + "s";
} else {
retval = seconds + "s";
} return retval + ms;
} public static void main(String[] args) {
RecordChanger rc=new RecordChanger();
rc.changeOnePencent("hy_test");
} protected class DBParam {
public final static String Driver = "oracle.jdbc.driver.OracleDriver";
public final static String DbUrl = "jdbc:oracle:thin:@dev-dm-ufo.dev.un.local:2050/ufo";
public final static String User = "ufo";
public final static String Pswd = "test01";
}
}
--END-- 2020-01-06 16:43
【Oracle】SQL对某字段模糊查询,哪种方案最快?的更多相关文章
- Mybatis mysql 一个搜索框多个字段模糊查询 几种方法
第一种 or 根据搜索框给定的关键词,模糊搜索用户名和账号都匹配的用户集合 <select id="list" parameterType="com.user.Us ...
- sql整型字段模糊查询
select count(*) cnt from vhuiy where CAST(id as text) like'%12%'--id为int类型 更详细的链接:http://www.studyof ...
- MySQL单表多字段模糊查询
今天工作时遇到一个功能问题:就是输入关键字搜索的字段不只一个字段,比如 我输入: 超天才 ,需要检索出 包含这个关键字的 name . company.job等多个字段.在网上查询了一会就找到了答案. ...
- MySQL简单实现多字段模糊查询
我所做的商城项目前些时提了新需求,要求前台搜索商品除了能通过商品名称搜索到以外,还可以通过别个信息搜索,比如:商品编号.详情内容描述等等,类似于全文搜索了.我首先想到的就是lucene,但是对代码这样 ...
- MySQL单表多字段模糊查询解决方法 又折磨半天concat(字段不能为空,如为空则用IFNULL(字段,'');
SELECT `id`,`weixin_id`,`user_name`,`sex`,`area_id`,`address_near`,`phone`,`create_time`,`import_use ...
- Mysql 之实现多字段模糊查询
在一个table中有省,市,县,期,栋,单元,室几个字段,然后用户输入一个地址从表中的字段拼接起来进行模糊查询. 解决办法: <MySQL权威指南>中CONCAT的使用方法,在书中的对CO ...
- Mysql多字段模糊查询
MySQL同一字段多值模糊查询 一. 同一字段多值模糊查询,使用多个or进行链接,效率不高,但没有更好的解决方案.(有看到CHARINDEX 关键字,可查询结果并不是模糊,举个栗子 例如SELECT ...
- 通过带参数的Sql语句来实现模糊查询(多条件查询)
#region 通过带参数的Sql语句来实现模糊查询(多条件查询) StringBuilder sb = new StringBuilder("select * from books&quo ...
- 在SQL Server中用好模糊查询指令LIKE
简介:like在sql中的使用 在SQL Server中用好模糊查询指令LIKE 查询是SQL Server中重要的功能,而在查询中将Like用上,可以搜索到一些意想不到的结果和效果,like的神奇之 ...
随机推荐
- 《Python测试开发技术栈—巴哥职场进化记》—软件测试工程师“兵器库”
上文<Python测试开发技术栈-巴哥职场进化记>-初来乍到,请多关照 我们介绍了巴哥入职后见到了自己的导师华哥,第一次参加团队站会,认识了团队中的开发小哥哥和产品小姐姐以及吃到了公司的加 ...
- Visual Studio 2019预览,净生产力
本文章为机器翻译. https://blogs.msdn.microsoft.com/dotnet/2018/12/13/visual-studio-2019-net-productivity/ 该文 ...
- C#LeetCode刷题之#665-非递减数列( Non-decreasing Array)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3732 访问. 给定一个长度为 n 的整数数组,你的任务是判断在最 ...
- 【源码】RocketMQ如何实现获取指定消息
概要 消息查询是什么? 消息查询就是根据用户提供的msgId从MQ中取出该消息 RocketMQ如果有多个节点如何查询? 问题:RocketMQ分布式结构中,数据分散在各个节点,即便是同一Topic的 ...
- Android 用versionName判断版本大小(是否进行版本更新)
一般情况下都是用versionCode进行版本大小的判断从而进行判断是否进行app的更新,但是有可能从网站上爬下来的versionCode不准确,有的网站叫做build,所以用versionName进 ...
- SpringSecurity权限管理系统实战—六、SpringSecurity整合jwt
目录 SpringSecurity权限管理系统实战-一.项目简介和开发环境准备 SpringSecurity权限管理系统实战-二.日志.接口文档等实现 SpringSecurity权限管理系统实战-三 ...
- IDEA - 错误提示 Could not autowire. No beans of '' type found
工具: IntelliJ IDEA 2019.3.4 x64 Ultimate,maven项目: 现象:如下图所示,出现Could not autowire. No beans of '' type ...
- SpringMVC关于拦截器的使用
这个是基于之前的视图定位进行的. @ 目录 拦截器类:IndexInterceptor 配置拦截器 修改 index.jsp 效果 拦截器类:IndexInterceptor package inte ...
- 如何选择一台适合Java开发的电脑
前言 最近在群里有同学求推荐Java开发用的电脑,所以胖哥就出个简单的专题,用我贫瘠的电脑知识来帮助大家选择适合开发的电脑配置.因为家里的主机已经带不动两个 IDEA 了,更别提开个 Docker 啥 ...
- 推断(inference)和预测(prediction)
上二年级的大儿子一直在喝无乳糖牛奶,最近让他尝试喝正常牛奶,看看反应如何.三天过后,儿子说,好像没反应,我可不可以说我不对乳糖敏感了. 我说,呃,这个问题不简单啊.你知道吗,这在统计学上叫推断. 儿子 ...