T-SQL语句查询执行顺序

Posted 邪心魔佛一页书

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了T-SQL语句查询执行顺序相关的知识,希望对你有一定的参考价值。

注意:笔者经过实验和查阅资料,已在原作基础上做了部分更改。更改不代表原作观点,查看原作请点击下方链接。

原文出处:

作者:张龙豪

链接:http://www.cnblogs.com/knowledgesea/p/4177830.html

前言

数据库的查询执行,毋庸置疑是程序员必备技能之一,然而数据库查询执行的过程绚烂多彩,却是很少被人了解,今天哥哥要带你装逼带你飞,深入一下这sql查询的来龙去脉,为查询的性能优化处理打个基础,或许面试你也会遇到,预防不跪还是看看吧。

这篇博客,摒弃查询优化性能,作为其基础,只针对查询流程讲解剖析。

本片博客阐述的过程为

1、上一个标识过的sql语句,展示查询执行的流程

2、上一个流程图

3、做一个例子逐步深入分析,帮助理解

4、做一个装逼的总结

sql查询语句的处理步骤,代码清单

 
--查询组合字段
select (6)distinct (8)top(<top_specification>)(5)<select_list>
--连表
(1)from (1-J)<left_table><join_type> join <right_table> on <on_predicate>
        (1-A)<left_table><apply_type> apply <right_table_expression> as <alias>
        (1-P)<left_table> pivot (<pivot_specification>) as <alias>
        (1-U)<left_table> unpivot (<unpivot_specification>) as <alias>
--查询条件
(2)where <where_pridicate>
--分组
(3)group by <group_by_specification>
--分组条件
(4)having<having_predicate>
--排序
(7)order by<order_by_list>
 

说明:

1、顺序为有1-8,8个大步骤,1-J,1-A,1-P,1-U,为并行次序。如果不够明白,接下来我在来个流程图看看。

2、执行过程中也会相应的产生多个虚拟表(下面会有提到),以配合最终的正确查询。

sql查询语句的处理步骤,流程图

 注:上述流程图保留原作。经过实验和查阅资料,做如下修改:计算表达式为第5步,distinct为第6步,order by为第7步,top为第8步,应在order by之后

实例准备,创建表,插入数据,写要分析的实例查询语句

1、首先创建两个表

2、创建两个表,并插入表数据,脚本如下 

USE [test]
GO
/****** Object:  Table [dbo].[Member]    Script Date: 2014/12/22 14:05:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Member](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](30) NULL,
    [phone] [varchar](15) NULL,
 CONSTRAINT [PK_MEMBER] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[Order]    Script Date: 2014/12/22 14:05:17 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Order](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [member_id] [int] NULL,
    [status] [int] NULL,
    [createTime] [datetime] NULL,
 CONSTRAINT [PK_ORDER] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET IDENTITY_INSERT [dbo].[Member] ON 

GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (1, N\'张龙豪\', N\'18501733702\')
GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (2, N\'Jim\', N\'15039512688\')
GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (3, N\'Tom\', N\'15139512854\')
GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (4, N\'Lulu\', N\'15687425583\')
GO
INSERT [dbo].[Member] ([id], [Name], [phone]) VALUES (5, N\'Jick\', N\'13528567445\')
GO
SET IDENTITY_INSERT [dbo].[Member] OFF
GO
SET IDENTITY_INSERT [dbo].[Order] ON 

GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (1, 1, 3, CAST(0x0000A40900B3BBFB AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (2, 2, 1, CAST(0x0000A40900B3CEF2 AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (3, 3, 4, CAST(0x0000A40900B3D2D0 AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (4, 4, 0, CAST(0x0000A40900B3D660 AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (5, 5, 1, CAST(0x0000A40900B3D9B9 AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (6, 6, 2, CAST(0x0000A40900B3DFEA AS DateTime))
GO
INSERT [dbo].[Order] ([id], [member_id], [status], [createTime]) VALUES (7, NULL, 0, CAST(0x0000A40900E34971 AS DateTime))
GO
SET IDENTITY_INSERT [dbo].[Order] OFF
GO
ALTER TABLE [dbo].[Order] ADD  DEFAULT (getdate()) FOR [createTime]
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'编号\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Member\', @level2type=N\'COLUMN\',@level2name=N\'id\'
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'姓名\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Member\', @level2type=N\'COLUMN\',@level2name=N\'Name\'
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'电话\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Member\', @level2type=N\'COLUMN\',@level2name=N\'phone\'
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'会员表\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Member\'
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'编号\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Order\', @level2type=N\'COLUMN\',@level2name=N\'id\'
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'会员编号\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Order\', @level2type=N\'COLUMN\',@level2name=N\'member_id\'
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'订单状态\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Order\', @level2type=N\'COLUMN\',@level2name=N\'status\'
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'下单日期\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Order\', @level2type=N\'COLUMN\',@level2name=N\'createTime\'
GO
EXEC sys.sp_addextendedproperty @name=N\'MS_Description\', @value=N\'订单表\' , @level0type=N\'SCHEMA\',@level0name=N\'dbo\', @level1type=N\'TABLE\',@level1name=N\'Order\'
GO
View Code 

3、编写咱们要解析的查询语句,即本篇要查询的实例语句。

 
select top(4)  status , max(m.id) as maxMemberID
from [dbo].[Member] as m right outer join [dbo].[Order] as o 
on m.id=o.member_id  where m.id>0
group by status 
having status>=0
order by maxMemberID asc
 

实例语句分步骤分析

第一步,从from开始。

1.1、加载左表

from [dbo].[Member] as m 

查询结果:member表中的所有数据

1.2、这里应该是 right outer join ,但是这里在sql中被定义分解为2个步骤,即join ,right outer join 。表达式关键字从左到右,依次执行。

join [dbo].[Order] as o 

查询结果:存入虚拟表vt1,为两个表的笛卡尔集合。这里你或许不明白什么叫笛卡尔集合,我打个比方给说说,还望不要嫌弃,就是小朋友握手问题,A班里有3个学生(看作一个表的三条数据),B班里有2个学生(看作另外一个表的2条数据).B班小朋友跟A班小朋友搞联欢晚会,首先要每个人都要确保跟另外一个班的同学我一下手,那么交叉出来的集合就是(2*3=6)有6条不同的轨迹。这个轨迹的集合就是笛卡尔集合。如果你还不明白,我再说下,就是m(5条数据)表中的第一条数据跟o(7条数据)表中的所有数据握下手,有7条,然后依次类推共有35条不同的数据。这里的null值也是要加进来的。

1.3、on 筛选器

on m.id=o.member_id 

查询结果:从上一步的笛卡尔集合35条数据中删除掉不匹配的行,就得到啦5条数据,存入虚拟表Vt2

1.4、添加外部行(outer row)

right outer join [dbo].[Order] as o 

查询结果为:右表(order)作为保留表,把剩余的数据重新添加到上一步的虚拟表中vt2,生成虚拟表vt3.

扫盲贴:T-SQL语句执行顺序

MSSQLSERVER执行计划详解

MSSQL·查询T-SQL语句执行时间的三种方法

shell if 语句

T-SQL 嵌套子查询

T-SQL 高级查询