【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的神奇之 ...
随机推荐
- 3、Java 对象和类
1.理解Java中的类和对象 对象: 作为学习计算机专业的很有意思,跟朋友开玩笑说,我有很多对象,没有就new一个.对象可以说是类的实例,通过类的构造方法得到的一个对象实例.它拥有此对象应有的行为与方 ...
- 精讲RestTemplate第4篇-DELETE、PUT等请求方法使用详解
本文是精讲RestTemplate第5篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 精讲RestTemplate第2篇-多种底层H ...
- 2020-05-24:ZK分布式锁有几种实现方式?各自的优缺点是什么?
福哥答案2020-05-24: Zk分布式锁有两种实现方式一种比较简单,应对并发量不是很大的情况.获得锁:创建一个临时节点,比如/lock,如果成功获得锁,如果失败没获得锁,返回false释放锁:删除 ...
- md文件批量转化为html
任务描述 博客的源文件一般以md文件保存 读取md源文件解析为html代码,然后嵌入到body中去 公式部分,需要使用第三方js库加载 实现办法 基于Django实现,进入webpage页面,然后通过 ...
- 封装react antd的upload上传组件
上传文件也是我们在实际开发中常遇到的功能,比如上传产品图片以供更好地宣传我们的产品,上传excel文档以便于更好地展示更多的产品信息,上传zip文件以便于更好地收集一些资料信息等等.至于为何要把上传组 ...
- 基于pcntl的PHP进程池
想必大家都知道可以通过多进程或者多线程的方式实现异步. PHP多进程编程当前主要有这几种方式, 1>基于pcntl实现多进程,这也是PHP自带的多进程玩法 2>Swoole自己修改PHP内 ...
- c/c++ 感悟 2008-10-03 02:08
许久没有坐在电脑前写东西了.除了密密麻麻的英文小虫子,还是英文小虫子.今天不是解决bug,明天就是在创造bug,一句话不在bug中沉默就在bug中爆发.或许喜欢小宇宙爆发的样子吧,那样的感觉总是让人热 ...
- 笔记:phpstudy、虚拟机CentOS安装、Linux命令
一.phpstudy 1.phpstudy实现w(Windows)a(Apache)m(Mysql)p(php)环境 Apache 用来发布Web服务 80端口 MySQL 开源的建议灵活的 ...
- 文章目录&友情链接
文章目录&友情链接 1:<公告:本博客开始写博文了> 2.本人网络图书馆
- 第二篇 Scrum冲刺博客
一.会议图片 二.项目进展 成员 完成情况 今日任务 冯荣新 搜索框,首页轮播图,分类导航 商品列表,商品详情轮播图 陈泽佳 背景展示,选择并显示图片 历史足迹,静态页面 徐伟浩 登录权限获取 商品信 ...