问题:有一张表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对某字段模糊查询,哪种方案最快?的更多相关文章

  1. Mybatis mysql 一个搜索框多个字段模糊查询 几种方法

    第一种 or 根据搜索框给定的关键词,模糊搜索用户名和账号都匹配的用户集合 <select id="list" parameterType="com.user.Us ...

  2. sql整型字段模糊查询

    select count(*) cnt from vhuiy where CAST(id as text) like'%12%'--id为int类型 更详细的链接:http://www.studyof ...

  3. MySQL单表多字段模糊查询

    今天工作时遇到一个功能问题:就是输入关键字搜索的字段不只一个字段,比如 我输入: 超天才 ,需要检索出 包含这个关键字的 name . company.job等多个字段.在网上查询了一会就找到了答案. ...

  4. MySQL简单实现多字段模糊查询

    我所做的商城项目前些时提了新需求,要求前台搜索商品除了能通过商品名称搜索到以外,还可以通过别个信息搜索,比如:商品编号.详情内容描述等等,类似于全文搜索了.我首先想到的就是lucene,但是对代码这样 ...

  5. MySQL单表多字段模糊查询解决方法 又折磨半天concat(字段不能为空,如为空则用IFNULL(字段,'');

    SELECT `id`,`weixin_id`,`user_name`,`sex`,`area_id`,`address_near`,`phone`,`create_time`,`import_use ...

  6. Mysql 之实现多字段模糊查询

    在一个table中有省,市,县,期,栋,单元,室几个字段,然后用户输入一个地址从表中的字段拼接起来进行模糊查询. 解决办法: <MySQL权威指南>中CONCAT的使用方法,在书中的对CO ...

  7. Mysql多字段模糊查询

    MySQL同一字段多值模糊查询 一. 同一字段多值模糊查询,使用多个or进行链接,效率不高,但没有更好的解决方案.(有看到CHARINDEX 关键字,可查询结果并不是模糊,举个栗子 例如SELECT ...

  8. 通过带参数的Sql语句来实现模糊查询(多条件查询)

    #region 通过带参数的Sql语句来实现模糊查询(多条件查询) StringBuilder sb = new StringBuilder("select * from books&quo ...

  9. 在SQL Server中用好模糊查询指令LIKE

    简介:like在sql中的使用 在SQL Server中用好模糊查询指令LIKE 查询是SQL Server中重要的功能,而在查询中将Like用上,可以搜索到一些意想不到的结果和效果,like的神奇之 ...

随机推荐

  1. linxu系统安装WordPress

    确保在安装wordpress之前,安装了nginx,php,mysql 没有安装的翻我之前的博文有安装方法 进入官网下载压缩包 wget https://wordpress.org/latest.ta ...

  2. CSS概述(二)

    目录 CSS背景属性 设置背景颜色 background-color 设置背景图像 background-image 设置背景重复 background-repeat 设置背景定位 backgroun ...

  3. 2020-03-27:JDK1.8中在数据结构上,对HashMap做了什么样的改进?为什么?

    福哥答案2020-04-04:头插改尾插,解决链表成环的问题.链表改成链表和红黑树.

  4. C#LeetCode刷题之#566-重塑矩阵( Reshape the Matrix)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3720 访问. 在MATLAB中,有一个非常有用的函数 resha ...

  5. SpringMVC大威天龙

    一 SpringMVC简介 SpringMVC是Spring提供的一个强大而灵活的Web框架 借助于注解 SpringMVC提供了几乎是POJO的开发模式 使得控制器的开发和测试更加简单 二 Spri ...

  6. Spark从入门到放弃---RDD

    什么是Spark? 关于Spark具体的定义,大家可以去阅读官网或者百度关于Spark的词条,在此不再赘述.从一个野生程序猿的角度去理解,作为大数据时代的一个准王者,Spark是一款主流的高性能分布式 ...

  7. 微信小程序之蓝牙广播信息

    期初第一次做蓝牙开锁的时候遇到的最尖锐的问题就是ios设备如何对获取的广播信息进行读取,大概用了4中方式,都无法解决,最后不得不求助官方人员.给了一个方法,大家可以参考.在此附图: 由于mac地址是6 ...

  8. linux zip压缩文件忽略指定的文件夹

    zip -r productImages.zip ./* -x "cache**" 压缩时,会忽略cache下的所有文件及文件夹

  9. windows 下apache开启FastCGI

    1.首先去(http://www.apachelounge.com/download/)下载一个合适的mod_fcgid  文件.     2.将解压后的文件改为mod_fcgid.dll 并复制到a ...

  10. 什么是RPC,RPC好处,常用的RPC框架

    RPC简介 RPC(Remote Procedure Call Protocol)远程过程调用协议.一个通俗的描述是:客户端在不知道调用细节的情况下,调用存在于远程计算机上的某个对象,就像调用本地应用 ...