SQL Server-聚焦INNER JOIN AND IN性能分析(十四)

原文:SQL Server-聚焦INNER JOIN AND IN性能分析(十四)

前言

本节我们来讲讲联接综合知识,我们在大多教程或理论书上都在讲用哪好,哪个性能不如哪个的性能,但是真正讲到问题的实质却不是太多,所以才有了本系列每一篇的篇幅不是太多,但是肯定是我用心去查找许多资料而写出,简短的内容,深入的理解,Always to review the basics。

初次探讨INNER JOIN和IN性能分析

接下来我们看第一篇联接综合知识讲解INNER JOIN和IN的比较分析,我们通过创建表来看INNER JOIN。

创建测试表1

CREATE TABLE Table1  (
 id INT IDENTITY PRIMARY KEY,
 SomeColumn CHAR(4),
 Filler CHAR(100)
)

插入测试数据

Insert into Table1(SomeColumn) Values (1),(2),(3),(4),(5)

创建测试表2并插入数据

USE TSQL2012
GO

CREATE TABLE Table2  (IntCol int)
Insert into Table2 (IntCol) Values (1),(2),(2),(3),(4),(5),(5)

接下来我们对测试表1和测试表2中的SomeColumn和IntCol进行JOIN

USE TSQL2012
GO

SELECT *
FROM Table1 b
 INNER JOIN Table2 s ON b.SomeColumn = s.IntCol

此时我们看到两个测试表中都返回7行数据,因为在测试表2中有重复的数据都匹配上所有测试表1返回所有数据。此时我们再来看看IN的查询

USE TSQL2012
GO

SELECT *
 FROM Table1
 WHERE SomeColumn IN (Select IntCol FROM Table2)

此时则返回5条数据,从这里我们知道INNER JOIN和IN还是有很大的区别,但是若在测试表2中没有重复的数据,同时在测试表2中没有需要的列,此时则查询出的数据和测试表1是一样的,此时二者在性能上有什么区别呢?接下来我们在创建大量数据的前提下来进行测试看看。

创建两个测试表

CREATE TABLE BigTable (
id INT IDENTITY PRIMARY KEY,
SomeColumn UNIQUEIDENTIFIER NOT NULL,
Filler CHAR(100)
)

CREATE TABLE SmallerTable (
id INT IDENTITY PRIMARY KEY,
LookupColumn UNIQUEIDENTIFIER NOT NULL,
SomeArbDate DATETIME DEFAULT GETDATE()
)

在BigTable表SomeColumn列中插入100万条数据

INSERT INTO BigTable (SomeColumn)
SELECT NEWID()
FROM dbo.Nums
WHERE n<1000001

取出BigTable中的25%数据插入到SmallerTable表LookupColumn列中

USE TSQL2012
GO

INSERT INTO SmallerTable (LookupColumn)
SELECT DISTINCT SomeColumn
FROM BigTable TABLESAMPLE (25 PERCENT)

这里我们分三种情况来测试。

(1)未建立索引比较INNER和JOIN

SELECT BigTable.ID, SomeColumn
FROM BigTable
WHERE SomeColumn IN (SELECT LookupColumn FROM dbo.SmallerTable)

SELECT BigTable.ID, SomeColumn
FROM BigTable
INNER JOIN SmallerTable ON dbo.BigTable.SomeColumn = dbo.SmallerTable.LookupColumn

 

从上看出此时在无论是查询开销还是IO上均没有什么差异,下面我们再来看看建立索引的情况

(2)建立非唯一非聚集索引比较INNER JOIN和IN

CREATE INDEX idx_BigTable_SomeColumn ON BigTable (SomeColumn)
CREATE INDEX idx_SmallerTable_LookupColumn ON SmallerTable (LookupColumn)

此时我们发现在建立非唯一非聚集索引的情况二者在查询开销上开始有了比较大的差异,INNER JOIN的开销是IN的两倍而IO几乎是等同的。

(3)建立唯一非聚集索引比较INNER JOIN和IN

CREATE UNIQUE INDEX idx_BigTable_SomeColumn ON BigTable (SomeColumn)
CREATE UNIQUE INDEX idx_SmallerTable_LookupColumn ON SmallerTable (LookupColumn)

此时为何索引变为唯一聚集索引二者性能开销却一致了呢?有点纳闷,同时到这里为止是不是说明IN的查询性能比JOIN的性能更好呢,完全颠覆我们的想法,在本文前言我们讨论过在教程中都会给出大部分JOIN比EXISTS性能好,而EXISTS比IN性能好,凡是还是动手实践,亲自验证才是王道,我们只能得出一般性结论:一般来说,JOIN比EXISTS性能好,而EXISTS比IN性能好仅此而已。这都是一般性情况,本系列需要讲述的是什么时候应该用EXISTS,什么时候应该用JOIN,还有什么时候应该用IN,后续内容会陆续讨论这些内容。好了,有点跑题了,上述我们通过100万条数据得出IN的性能接近是INNER JOIN性能的两倍,完全出乎你我的意料,带着这个疑问,接下来我们进一步进行探讨。

进一步探讨INNER JOIN和IN性能分析 

上述在SmallerTable表从BigTable表中取出的25%的数据都是唯一的,接下来我们将这25%数据的一部分设置为重复的。我们随便从BigTable表中取出SomeColumn这列的数据,然后将SmallerTable表中的LookupColumn这列的数据设置重复的10000条,如下

USE TSQL2012
GO

UPDATE dbo.SmallerTable SET LookupColumn = '0067cb6c-64e1-46cc-b7f2-334a7dd812ff'
WHERE id>=1 AND id<=10000

此时我们查询包括重复的这10000条

USE TSQL2012
GO

SELECT BigTable.ID, SomeColumn
FROM BigTable
WHERE SomeColumn IN (SELECT LookupColumn FROM dbo.SmallerTable)

SELECT BigTable.ID, SomeColumn
FROM BigTable
INNER JOIN SmallerTable ON dbo.BigTable.SomeColumn = dbo.SmallerTable.LookupColumn

此时结果还是IN性能比INNER JOIN性能要接近一半,接下来我们在查询SmallerTable表时将重复的LookupColumn列数据去除,此时我们查询变为如下:

USE TSQL2012
GO

SELECT BigTable.ID, SomeColumn
FROM BigTable
WHERE SomeColumn IN (SELECT LookupColumn FROM dbo.SmallerTable)

SELECT BigTable.ID, SomeColumn
FROM BigTable
INNER JOIN (SELECT DISTINCT LookupColumn FROM dbo.SmallerTable) AS s
ON s.LookupColumn = dbo.BigTable.SomeColumn

终于查询开销和上述不一样了,此时二者查询性能开销是一致的,相信到了这里我们应该很清楚了。通过上述大量篇幅的贴图和比较我们可以得出INNER JOIN和IN的性能开销使用场景,当我们在初步探讨INNER JOIN和IN的性能分析时,当建立非唯一聚集索引时IN性能接近是INNER JOIN的两倍,而当建立唯一聚集索引时,此时性能开销一致,不免有点纳闷,当我们继续向下探讨时终于明白了这个原因,至此我们最终得出INNER JOIN和IN的性能开销结论。

INNER JOIN和IN性能开销结论:当INNER JOIN表中列数据是唯一的,此时INNER JOIN和IN的性能开销是相同的,当INNER JOIN表中列数据是重复的,此时IN性能要INNER JOIN要好。

总结

本节我们详细叙述了INNER JOIN和IN的性能分析,最终得出一致性结论,下节我们开始讨论NOT EXISTS和NOT IN性能分析,简短的内容,深入的理解,我们下节再会,good night。

时间: 2024-09-11 23:46:31

SQL Server-聚焦INNER JOIN AND IN性能分析(十四)的相关文章

SQL Server中INNER JOIN与子查询IN的性能测试

这个月碰到几个人问我关于"SQL SERVER中INNER JOIN 与 IN两种写法的性能孰优孰劣?"这个问题.其实这个概括起来就是SQL Server中INNER JOIN与子查询孰优孰劣(IN是子查询的实现方式之一,本篇还是只对比INNER JOIN与子查询IN的性能,如果展开INNER JOIN与子查询性能对比,范围太大了,没法一一详述).下面这篇文章,我们就INNER JOIN与子查询IN这两种写法孰优孰劣,在不同场景下进行一下测试对比一下,希望能解答你心中的疑惑.   下面

SQL Server-聚焦NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL性能分析(十八)

前言 本节我们来综合比较NOT IN VS NOT EXISTS VS LEFT JOIN...IS NULL的性能,简短的内容,深入的理解,Always to review the basics. NOT IN.NOT EXISTS.LEFT JOIN...IS NULL性能分析 我们首先创建测试表 USE TSQL2012 GO CREATE SCHEMA [compare] CREATE TABLE [compare].t_left ( id INT NOT NULL PRIMARY KE

SQL Server中一个隐性的IO性能杀手-Forwarded record

原文:SQL Server中一个隐性的IO性能杀手-Forwarded record 简介     最近在一个客户那里注意到一个计数器很高(Forwarded Records/Sec),伴随着间歇性的磁盘等待队列的波动.本篇文章分享什么是forwarded record,并从原理上谈一谈为什么Forwarded record会造成额外的IO.   存放原理     在SQL Server中,当数据是以堆的形式存放时,数据是无序的,所有非聚集索引的指针存放指向物理地址的RID.当数据行中的变长列增

sql server的across join语句怎么用?用它怎么取分组结果的第一条记录呢?

问题描述 sql server的across join语句怎么用?用它怎么取分组结果的第一条记录呢? sql server的across join语句怎么用?用它怎么取分组结果的第一条记录呢? 解决方案 http://www.2cto.com/database/201509/442742.html 解决方案二: http://zhidao.baidu.com/link?url=zu-YuSRPF-4RKb_yrqC7cZm4Smbz_pWS31ltTFn6HIknGbUHgcOtH8FavG9o

几种SQL Server分页的存储过程写法以及性能比较

几种SQL Server分页的存储过程写法以及性能比较 存储过程的5种分页写法,下面的代码是从忘了什么时候从别人那Ctrl+C来的,所以仅仅作为收藏,希望作者看到不要喷我.  ------创建数据库教程data_Test ----- create database data_Test  GO use data_Test GO create table tb_TestTable   --创建表 (     id int identity(1,1) primary key,     userName

SQL Server的Inner Join及Outer Join

当然 Join 如何将不同的数据库的资料结合, 还要看你如何使用它, 一共有四种不同的 Join 的方式, 在这篇文章中我们将为你介绍 Inner Join 及 Outer Join 以及其应用. 在一个正规化的数据库环境中, 我们常会碰到这款情形: 所需的资料并不是放在同一个资料表中, 在这个时候, 你就要用到 Join. 当然 Join 如何将不同的数据库的资料结合, 还要看你如何使用它, 一共有四种不同的 Join 的方式, 在这篇文章中我们将为你介绍 Inner Join 及 Outer

Forwarded record:SQL Server中一个隐性的IO性能杀手

简介 最近在一个客户那里注意到一个计数器很高(Forwarded Records/Sec),伴随着间歇性的磁盘等待队列的波动.本篇文章分享什么是forwarded record,并从原理上谈一谈为什么Forwarded record会造成额外的IO. 存放原理 在SQL Server中,当数据是以堆的形式存放时,数据是无序的,所有非聚集索引的指针存放指向物理地址的RID.当数据行中的变长列增长使得原有页无法容纳下数据行时,数据将会移动到新的页中,并在原位置留下一个指向新页的指针,这么做的原因是由

SQL Server与Oracle、DB2的性能比较

开放性 SQL Server 只能在Windows 上运行,没有丝毫的开放性,操作系统的系统的稳定对数据库是十分重要的.Windows9X系列产品是偏重于桌面应用,NT server只适合中小型企业.而且Windows平台的可靠性,安全性和伸缩性是非常有限的.它不象Unix那样久经考验,尤其是在处理大数据量的关键业务时. Oracle 能在所有主流平台上运行(包括 Windows).完全支持所有的工业标准.采用完全开放策略.可以使客户选择最适合的解决方案.对开发商全力支持. DB2 能在所有主流

sql server几种Join的区别测试方法_MsSql

主要来介绍下Inner Join , Full Out Join , Cross Join , Left Join , Right Join的区别. Inner Join:筛选两边都有的记录 Full Out Join:两边都筛选出来,匹配能匹配的,不能匹配的用NULL列出 Cross Join:列出两边所有组合,也称为笛卡尔集 A×B Left Join:以左边的表为主表,列出主表所有记录,匹配能匹配的,不能匹配的用 NULL列出 Right Join:以右边的表为主表,列出主表所有记录,匹配