SQL Server ->> 条件筛选做法之 -- IN(VALUE1,VALUE2,...)与INNER JOIN STRING_SPLIT()性能对比...

本文通过实例比较了在SQL查询中使用IN关键字与INNER JOIN在处理大量数据时的不同性能表现,尤其是在I/O操作方面。

在以逗号拼接而成的字符串,传入给IN字句的元素字符串中包涵了1400多个元素

两种做法分别为 

AND e.ssPfCityId IN (
SELECT
CAST(value AS INT)
FROM STRING_SPLIT('110000,310000,120000,210100,210200,210400,210800,211200,350100,350500,350200,350800,350700,350900,441200,441300,440500,445100,450100,451000,450800,450300,451100,450200,450900,450500,450400,450600,460100,510100,...'
,',')
)

 

INNER JOIN (SELECT DISTINCT CAST(value AS INT) AS VALUE FROM STRING_SPLIT('110000,310000,120000,210100,210200,210400,210800,211200,350100,350500,350200,350800,350700,350900,441200,441300,440500,445100,450100,451000,450800,450300,451100,450200,450900,450500,450400,450600,460100,510100,...',',') T) T ON e.ssPfCityId = T.VALUE

 

 

对比看出如果用IN字句会用一个HASH MATCH的聚合操作符,而用INNER JOIN则用DISTINCT SORT。

 

 

而如果对比IO统计数据可以发现IN字句的做法多出了许多Workfile产生的IO

(128478 行受影响)

表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 577 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'Workfile'。扫描计数 70,逻辑读取 2424 次,物理读取 172 次,预读 2268 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'employee'。扫描计数 9,逻辑读取 4559 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'verifyProcess'。扫描计数 9,逻辑读取 3136 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

 

而用INNER JOIN则么有Workfile产生的IO

(128478 行受影响)
表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'Workfile'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'employee'。扫描计数 9,逻辑读取 4559 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
表 'verifyProcess'。扫描计数 9,逻辑读取 3136 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。

 

这个例子的性能看上去总时间开销差别并不是很明显,因为连接的表数量少,而如果连接的表数量多起来,可能整个执行计划会是另一回事,那个时候IN字句的弊端就显现了。

转载于:https://www.cnblogs.com/jenrrychen/p/7064504.html

package cn.itcast.edu.analysis import cn.itcast.edu.bean.Answer import cn.itcast.edu.utils.RedisUtil import com.google.gson.Gson import org.apache.kafka.common.serialization.StringDeserializer import org.apache.spark.ml.recommendation.ALSModel import org.apache.spark.sql.functions.udf import org.apache.spark.{SparkContext, streaming} import org.apache.spark.sql.{SaveMode, SparkSession} import org.apache.spark.streaming.StreamingContext import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies} import java.util.Properties object StreamingRecommend { def main(args: Array[String]): Unit = { val spark:SparkSession = SparkSession.builder() .appName("streamingrecommend") .master("local[*]") .config("spark.sql.shuffle.partitions", "3") .getOrCreate() val sc:SparkContext = spark.sparkContext val ssc:StreamingContext = new StreamingContext( sc, streaming.Seconds(5) ) import spark.implicits._ val kafkaParams = Map[String, Object]( "bootstrap.servers" -> "hadoop01:9092,hadoop02:9092", "key.deserializer" -> classOf[StringDeserializer], "value.deserializer" -> classOf[StringDeserializer], "group.id" -> "StreamingRecommend", ) val topic = Array("edu") val kafkaDStream = KafkaUtils.createDirectStream[String, String]( ssc, LocationStrategies.PreferConsistent, ConsumerStrategies.Subscribe[String, String](topic, kafkaParams) ) //获取Redis连接配置,并读取存储在Redis中推荐模型的存储路径 kafkaDStream.map(_.value()).foreachRDD(rdd => { if (!rdd.isEmpty()) { val jedis = RedisUtil.pool.getResource val path = jedis.hget( "model", "recommended_question_id" ) //加载推荐模型 val model = ALSModel.load(path) //解析JSON格式的数据,将解析的数据样例类Answer中的字段进行映射 val answerDF = rdd.coalesce(1) .map(josnStr => { val gson = new Gson() gson.fromJson(josnStr, classOf[Answer]) }).toDF() val id = udf((student_id: String) => { student_id.split("_")(1).toInt }) val studentIdDF = answerDF.select( id ($"student_id") as "student_id" ) val recommendDF = model.recommendForUserSubset( studentIdDF, 10 ) val recommendResultDF = recommendDF .as[(Int, Array[(Int, Float)])] .map(t => { val studentIdStr = "学生ID_" + t._1 val questionIdsStr = t._2.map("题目ID_" + _._1) .mkString(",") (studentIdStr, questionIdsStr) }).toDF("student_id", "recommendations") val allInfoDF = answerDF.join( recommendResultDF, "student_id" ) allInfoDF.show(false) if (allInfoDF.count() > 0) { val properties = new Properties() properties.setProperty("user", "root") properties.setProperty("password", "123456") allInfoDF .write .mode(SaveMode.Append) .jdbc( "jdbc:mysql://hadoop01:3306/edu?" + "createDatabaseIfNotExist=true&" + "useUnicode=true&characterEncoding=utf8", "t_recommended", properties ) } jedis.close() } } ) //启动StreamingContext ssc.start() //使StreamingContext持续运行,除非人为干预停止 ssc.awaitTermination() ssc.stop(stopSparkContext = true, stopGracefully = true) } }
06-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值