内连接(INNER JOIN):在SELECT语句中用来从多个表中返回单个结果集。JOIN在一个共有列上链接表,并返回在那个列上匹配的记录。只有两个表之间有匹配的记录才会出现在结果集中。
外连接(OUTER JOIN):有3种类型:左连接、右连接、全连接。
左连接:了解JOIN左边的表中的所有记录,而不管他们在右边表中是否有匹配的记录。右连接相反。
全连接:同时查看左表和右表中的所有的记录,而不管它们在另一表中是否有对应的记录。
聚集索引和非聚集索引的区别:汉语字典的正文本身就是一个聚集索引。比如,我们要查“安”字,就会很自然地翻开字典的前几页,因为“安”的拼音是“an”,而按照拼音排序汉字的字典是以英文字母“a”开头并以“z”结尾的,那么“安”字就自然地排在字典的前部。如果您翻完了所有以“a”开头的部分仍然找不到这个字,那么就说明您的字典中没有这个字;同样的,如果查“张”字,那您也会将您的字典翻到最后部分,因为“张”的拼音是“zhang”。也就是说,字典的正文部分本身就是一个目录,您不需要再去查其他目录来找到您需要找的内容。正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。
如果您认识某个字,您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,而需要去根据“偏旁部首”查到您要找的字,然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合“部首目录”和“检字表”而查到的字的排序并不是真正的正文的排序方法,比如您查“张”字,我们可以看到在查部首之后的检字表中“张”的页码是672页,检字表中“张”的上面是“驰”字,但页码却是63页,“张”的下面是“弩”字,页面是390页。很显然,这些字并不是真正的分别位于“张”字的上下方,现在您看到的连续的“驰、张、弩”三字实际上就是他们在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字,但它需要两个过程,先找到目录中的结果,然后再翻到您所需要的页码。
我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为“非聚集索引”。
通过以上例子,我们可以理解到什么是“聚集索引”和“非聚集索引”。
进一步引申一下,我们可以很容易的理解:每个表只能有一个聚集索引,因为目录只能按照一种方法进行排序。
得出查询速度的方法是:在各个select语句前加:declare @d datetime
set @d=getdate()
并在select语句后加:
select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())
1、用聚合索引比用不是聚合索引的主键速度快
2、用聚合索引比用一般的主键作order by时速度快,特别是在小数据量情况下
事实上,如果数据量很小的话,用聚集索引作为排序列要比使用非聚集索引速度快得明显的多;而数据量如果很大的话,如10万以上,则二者的速度差别不明显。
3、使用聚合索引内的时间段,搜索时间会按数据占整个数据表的百分比成比例减少,而无论聚合索引使用了多少个
4 、日期列不会因为有分秒的输入而减慢查询速度
从publish 表中取出第 n 条到第 m 条的记录:
SELECT TOP m-n+1 *
FROM publish
WHERE (id NOT IN
(SELECT TOP n-1 id
FROM publish))
id 为publish 表的关键字
只所以把“查询优化”和“分页算法”这两个联系不是很大的论题放在一起,就是因为二者都需要一个非常重要的东西――聚集索引。
在前面的讨论中我们已经提到了,聚集索引有两个最大的优势:
1、以最快的速度缩小查询范围。
2、以最快的速度进行字段排序。
第1条多用在查询优化时,而第2条多用在进行分页时的数据排序。
而聚集索引在每个表内又只能建立一个,这使得聚集索引显得更加的重要。聚集索引的挑选可以说是实现“查询优化”和“高效分页”的最关键因素。
但要既使聚集索引列既符合查询列的需要,又符合排序列的需要,这通常是一个矛盾。
聚集索引是如此的重要和珍贵,所以一定要将聚集索引建立在:
1、您最频繁使用的、用以缩小查询范围的字段上;
2、您最频繁使用的、需要排序的字段上。
导读:本文主要涉及Service Broker的基本概念及建立一个Service Broker应用程序的基本步骤。
一、前言:
Service Broker为SQL Server提供消息队列,这提供了从数据库中发送异步事务性消息队列的方法。Service Broker消息可以保证以适当的顺序或原始的发送顺序不重复地一次性接收。并且因为内建在SQL Server中,这些消息在数据库发生故障时是可以恢复的,也可以随数据库一起备份。在SQL Server 2008中,还引入了使用Create Broker Priority命令对会话设定优先级,可以对重要的或不重要的会话进行优先级设定,以保证消息合理地处理。
本文假定一个在线数据库BookStore中存储了一些业务订单。我们使用Service Broker应用程序将消息发送到另一个数据库BookDistribution,该数据库是分离的应用程序调用,该应用程序控制仓库入库和出库交付, 并返回消息给BookStore。
创建Service Broker应用程序大体步骤如下:
1、定义希望应用程序执行的异步任务。
2、确定Service Broker的发起方服务和目标服务是否创建在同一个SQL Server实例中。如果是两个实例,实例间的通信还需要创建经过证书认证或NT安全的身份认证,并且要创建端点、路由以及对话安全模式。
3、如果没有启用,则在多方参与的数据库中使用Alter Database命令设置Enable_broker以及Truseworthy数据库选项。
4、为所有多方参与的数据库创建数据库主密钥。
5、创建希望在服务之间发送的消息类型。
6、创建契约(Contract)来定义可以由发起方发送的各种消息以及由目标发送的消息类型的种类。
7、同时在两方参与的数据库中创建用于保存消息的队列。
8、同时在绑定特定约定到特定队列的多方参与的数据库中创建服务。
二、实例
下面我们通过一个示例来实现以上步骤:
(一)、启用数据库的Service Broker活动
- -- Enabling Databases for Service Broker Activity
- USE master
- GO
- IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'BookStore')
- CREATE DATABASE BookStore
- GO
- IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'BookDistribution')
- CREATE DATABASE BookDistribution
- GO
- ALTER DATABASE BookStore SET ENABLE_BROKER
- GO
- ALTER DATABASE BookStore SET TRUSTWORTHY ON
- GO
- ALTER DATABASE BookDistribution SET ENABLE_BROKER
- GO
- ALTER DATABASE BookDistribution SET TRUSTWORTHY ON
(二)、创建数据库主密钥
- -- Creating the DatabaseMaster Key for Encryption
- USE BookStore
- GO
- CREATE MASTER KEY
- ENCRYPTION BY PASSWORD = 'I5Q7w1d3'
- GO
- USE BookDistribution
- GO
- CREATE MASTER KEY
- ENCRYPTION BY PASSWORD = 'D1J3q5z8X6y4'
- GO
(三)、管理消息类型
使用CREATE MESSAGE TYPE(http://msdn.microsoft.com/en-us/library/ms187744.aspx)命令,
- -- Managing Message Types
- Use BookStore
- GO
- -- 发送图书订单的消息类型
- CREATE MESSAGE TYPE [//SackConsulting/SendBookOrder]
- VALIDATION = WELL_FORMED_XML
- GO
- --目标数据库发送的消息类型
- CREATE MESSAGE TYPE [//SackConsulting/BookOrderReceived]
- VALIDATION = WELL_FORMED_XML
- GO
- --执行同样的定义
- Use BookDistribution
- GO
- -- 发送图书订单的消息类型
- CREATE MESSAGE TYPE [//SackConsulting/SendBookOrder]
- VALIDATION = WELL_FORMED_XML
- GO
- --目标数据库发送的消息类型
- CREATE MESSAGE TYPE [//SackConsulting/BookOrderReceived]
- VALIDATION = WELL_FORMED_XML
- GO
--注意,此处没有定义消息的内容。实际的消息是消息类型的实例。
(四)、创建契约(Contract)
使用Create Contract(http://msdn.microsoft.com/en-us/library/ms178528.aspx)
- -- Creating Contracts
- Use BookStore
- GO
- CREATE CONTRACT
- [//SackConsulting/BookOrderContract]
- ( [//SackConsulting/SendBookOrder]
- SENT BY INITIATOR,
- [//SackConsulting/BookOrderReceived]
- SENT BY TARGET
- )
- GO
- USE BookDistribution
- GO
- CREATE CONTRACT
- [//SackConsulting/BookOrderContract]
- ( [//SackConsulting/SendBookOrder]
- SENT BY INITIATOR,
- [//SackConsulting/BookOrderReceived]
- SENT BY TARGET
- )
- GO
--发起方和目标的定义必须相同
(五)、创建队列
队列用来保存数据。使用命令Create queue(http://msdn.microsoft.com/en-us/library/ms190495.aspx)
- -- Creating Queues
- Use BookStore
- GO
- --保存BookDistribution过来的消息
- CREATE QUEUE BookStoreQueue
- WITH STATUS=ON
- GO
- USE BookDistribution
- GO
- --保存BookStore过来的消息
- CREATE QUEUE BookDistributionQueue
- WITH STATUS=ON
- GO
(六)、创建服务
服务定义端点,然后使用它来将消息队列绑定到一个或多个契约上。服务使用队列和契约来定义一个或一组任务。有点拗口,是不是?
服务是消息的发起方和接收方强制约定的规则,并将消息路由到正确的序列。
使用Create Service(http://msdn.microsoft.com/en-us/library/ms190332.aspx)命令。
- -- Creating Services
- Use BookStore
- GO
- CREATE SERVICE [//SackConsulting/BookOrderService]
- ON QUEUE dbo.BookStoreQueue--指定的队列绑定到契约
- ([//SackConsulting/BookOrderContract])
- GO
- USE BookDistribution
- GO
- CREATE SERVICE [//SackConsulting/BookDistributionService]
- ON QUEUE dbo.BookDistributionQueue--指定的队列绑定到契约
- ([//SackConsulting/BookOrderContract])
- GO
(七)、启动对话
对话会话(dialog conservation)是在服务之间进行消息交换的操作。
使用Begin Dialog Conversation(http://msdn.microsoft.com/en-us/library/ms187377.aspx) 命令创建新的会话。使用Send(http://msdn.microsoft.com/en-us/library/ms188407.aspx)来发送消息。使用End Conversation命令(http://msdn.microsoft.com/en-us/library/ms177521.aspx)结束会话。
- -- Initiating a Dialog
- Use BookStore
- GO
- --保存会话句柄和订单信息
- DECLARE @Conv_Handler uniqueidentifier
- DECLARE @OrderMsg xml;
- BEGIN DIALOG CONVERSATION @Conv_Handler--创建会话
- FROM SERVICE [//SackConsulting/BookOrderService]
- TO SERVICE '//SackConsulting/BookDistributionService'
- ON CONTRACT [//SackConsulting/BookOrderContract];
- SET @OrderMsg =
- '<order id="3439" customer="22" orderdate="2/15/2011">
- <LineItem ItemNumber="1" ISBN="1-59059-592-0" Quantity="1" />
- </order>';
- SEND ON CONVERSATION @Conv_Handler--发送到BookDistribution数据库的队列中
- MESSAGE TYPE [//SackConsulting/SendBookOrder]
- (@OrderMsg);
(八)、查询队列中传入的消息
- -- Querying the Queue for IncomingMessages
- USE BookDistribution
- GO
- SELECT message_type_name, CAST(message_body as xml) message,
- queuing_order, conversation_handle, conversation_group_id
- FROM dbo.BookDistributionQueue
查询结果:
(九)、检索并响应消息
使用Receive语句(http://msdn.microsoft.com/en-us/library/ms186963.aspx)从队列中读取行(消息),也可以删除已经读取的消息。Receive的结果可以填充到常规表中,也可以在局部变量中执行其他操作,或发送到其他service Broker消息。如果消息是XML数据类型的消息,则可以直接借助TSQL的XQuery来操作。
- -- Receiving and Responding to aMessage
- USE BookDistribution
- GO
- --创建一个表存放接收到的订单信息
- CREATE TABLE dbo.BookOrderReceived
- (BookOrderReceivedID int IDENTITY (1,1) NOT NULL,
- conversation_handle uniqueidentifier NOT NULL,
- conversation_group_id uniqueidentifier NOT NULL,
- message_body xml NOT NULL)
- GO
- -- 声明变量
- DECLARE @Conv_Handler uniqueidentifier
- DECLARE @Conv_Group uniqueidentifier
- DECLARE @OrderMsg xml
- DECLARE @TextResponseMsg varchar(8000)
- DECLARE @ResponseMsg xml
- DECLARE @OrderID int;
- --从队列中获取消息,将接收值赋于局部变量
- RECEIVE TOP(1) @OrderMsg = message_body,--TOP指定最多一条消息
- @Conv_Handler = conversation_handle,
- @Conv_Group = conversation_group_id
- FROM dbo.BookDistributionQueue;
- -- 将变量值插入表中
- INSERT dbo.BookOrderReceived
- (conversation_handle, conversation_group_id, message_body)
- VALUES
- (@Conv_Handler,@Conv_Group, @OrderMsg )
- -- 使用XQuery进行抽取以响应消息订单
- SELECT @OrderID = @OrderMsg.value('(/order/@id)[1]', 'int' )
- SELECT @TextResponseMsg =
- '<orderreceived id= "' +
- CAST(@OrderID as varchar(10)) +
- '"/>';
- SELECT @ResponseMsg = CAST(@TextResponseMsg as xml);
- -- 使用既有的会话句柄,发送响应消息到发起方
- SEND ON CONVERSATION @Conv_Handler
- MESSAGE TYPE [//SackConsulting/BookOrderReceived](@OrderMsg)
(十)、结束会话
- -- Ending a Conversation
- USE BookStore
- GO
- -- 创建订单确认表
- CREATE TABLE dbo.BookOrderConfirmation
- (BookOrderConfirmationID int IDENTITY (1,1) NOT NULL,
- conversation_handle uniqueidentifier NOT NULL,
- DateReceived datetime NOT NULL DEFAULT GETDATE(),
- message_body xml NOT NULL)
- DECLARE @Conv_Handler uniqueidentifier
- DECLARE @Conv_Group uniqueidentifier
- DECLARE @OrderMsg xml
- DECLARE @TextResponseMsg varchar(8000);
- RECEIVE TOP(1) @Conv_Handler = conversation_handle,
- @OrderMsg = message_body
- FROM dbo.BookStoreQueue
- INSERT dbo.BookOrderConfirmation
- (conversation_handle, message_body)
- VALUES (@Conv_Handler,@OrderMsg );
- END CONVERSATION @Conv_Handler;
- GO
- USE BookDistribution
- GO
- DECLARE @Conv_Handler uniqueidentifier
- DECLARE @Conv_Group uniqueidentifier
- DECLARE @OrderMsg xml
- DECLARE @message_type_name nvarchar(256);
- RECEIVE TOP(1) @Conv_Handler = conversation_handle,
- @OrderMsg = message_body,
- @message_type_name = message_type_name
- FROM dbo.BookDistributionQueue
- -- 双方必须都结束会话
- IF
- @message_type_name = 'http://schemas.microsoft.com/SQL/ServiceBroker/EndDialog'
- BEGIN
- END CONVERSATION @Conv_Handler;
- END
- --查询会话状态
- SELECT state_desc, conversation_handle
- FROM sys.conversation_endpoints
三、小结
本文通过一个实例演示了一个用来发送图书订单消息分发控制数据库的简单的消息交换应用程序。发起方发送图书订单,发回一个响应,并在两个数据库上使用END Conservation结束会话。现实场景中可以转换为其他消息类型、契约、服务和队列。合理运用Service Broker应用程序的异步特性可以防止因应用程序挂起而导致业务系统产生瓶颈。