【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的神奇之 ...
随机推荐
- SpringBoot常用配置,引入外部配置文件信息,热加载
SpringBoot的配置文件格式 yml规范 SpringBoot的配置文件支持properties和yml,甚至还支持json. 更推荐使用yml文件格式: yml文件,会根据换行和缩进帮助咱们管 ...
- dom4j基本操作
DOM4J与利用DOM.SAX.JAXP机制来解析xml相比,DOM4J 表现更优秀,具有性能优异.功能强大和极端易用使用的特点,只要懂得DOM基本概念,就可以通过dom4j的api文档来解析xml. ...
- 恕我直言,你可能真没用过这些 IDEA 插件!
一.前言 IDEA 全称 IntelliJ IDEA,是java编程语言开发的集成环境.IntelliJ在业界被公认为最好的java开发工具. 不是我说的喔,百度百科说的... IDEA 如此好用,插 ...
- IE6和IE11之间 表单提交 按钮设置了disabled属性
JSP代码可以不看,就是一个表单,通过submit提交. <form action="mainAction.do?method=saveQuote" method=" ...
- Java—匿名对象/内部类/访问修饰符/代码块
匿名对象 匿名对象是指创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量. //创建一个普通对象 Person p = new Person(); //创建一个匿名对象 new Pers ...
- 微信小程序开发着工具获取和更新newticket
newticket是微信开发者工具和微信后台交互的凭证.大多数工具的操作都是需要newticket. 如何获取newticket? 打开开发者工具,依次点击菜单设置->通用设置->代理,使 ...
- 基于token的会话保持机制
session简介 做过Web开发的程序员应该对Session都比较熟悉,Session是一块保存在服务器端的内存空间,一般用于保存用户的会话信息. 用户通过用户名和密码登陆成功之后,服务器端程序会在 ...
- linux上传下载小工具lrzsz
工具压缩包链接 密码:zbef 1.将压缩包放到linux的任意目录下,执行:tar zxvf lrzsz-0.12.20.tar.gz 解压压缩包 2.cd lrzsz-0.12.20 3../co ...
- unity探索者之微信分享回调
版权声明:本文为原创文章,转载请声明http://www.cnblogs.com/unityExplorer/p/7574561.html 上一遍讲了微信分享的一些坑,然后就忘了回调这事儿了,今天补上 ...
- adb命令将抓包工具证书从用户目录移动至系统目录,解决反爬对于本地证书认证
代码和注释 adb shell #连接手机进入shell模式 #su root #如果你不root权限可以试着这个一般都是root cd /data/misc/user/0/cacerts-added ...