前言
上一节我们简单讲述了表表达式的4种类型,这一系列我们来讲讲使用视图的限制,简短的内容,深入的理解,Always to review the basics。
避免在视图中使用ORDER BY
上一节我们也讲述了使用表表达式必须满足的3个要求,其中就有一个无法保证顺序,也就是说的ORDER BY的问题,我们还是重点看看在视图中的限制。在常规查询中对于排序我们是这样做的。
USE AdventureWorks2012
GO
SELECT *
FROM Sales.SalesOrderDetail
ORDER BY SalesOrderDetailID DESC
接下来我们在视图中对数据进行排序,我们创建视图来看看
USE AdventureWorks2012
GO
IF EXISTS (SELECT * FROM sys.views WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[view_limit]'))
DROP VIEW [dbo].[view_limit] GO
CREATE VIEW view_limit
AS
SELECT *
FROM Sales.SalesOrderDetail
ORDER BY SalesOrderDetailID DESC
GO
此时当我们执行创建视图时会发现如下错误
此时在视图内部不能使用ORDER BY我们创建视图后在外部视图使用ORDER BY看看
USE AdventureWorks2012
GO
IF EXISTS (SELECT * FROM sys.views WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[view_limit]'))
DROP VIEW [dbo].[view_limit]
GO
CREATE VIEW view_limit
AS
SELECT *
FROM Sales.SalesOrderDetail
GO
SELECT *
FROM view_limit
ORDER BY SalesOrderDetailID DESC
USE AdventureWorks2012
GO
IF EXISTS (SELECT * FROM sys.views WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[view_limit]'))
DROP VIEW [dbo].[view_limit]
GO
CREATE VIEW view_limit
AS
SELECT TOP 100 PERCENT *
FROM Sales.SalesOrderDetail
ORDER BY SalesOrderDetailID DESC
GO
我们再来查询该视图看看返回的结果集
USE AdventureWorks2012
GO
SELECT *
FROM dbo.view_limit
IF EXISTS (SELECT * FROM sys.views WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[view_limit]'))
DROP VIEW [dbo].[view_limit]
GO
CREATE VIEW view_limit
AS
SELECT TOP 99.9 PERCENT *
FROM Sales.SalesOrderDetail
ORDER BY SalesOrderDetailID DESC
GO
USE AdventureWorks2012
GO
IF EXISTS (SELECT * FROM sys.views WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[view_limit]'))
DROP VIEW [dbo].[view_limit]
GO
CREATE VIEW view_limit
AS
SELECT *
FROM HumanResources.Shift
GO
接下来我们通过查找原表和视图的方式来看看返回的数据
USE AdventureWorks2012
GO
-- 查找原表
SELECT *
FROM HumanResources.[Shift]
GO
-- 查找视图
SELECT *
FROM view_limit
GO
恩,没毛病,接下来我们在表中添加额外列
USE AdventureWorks2012
GO
ALTER TABLE HumanResources.[Shift]
ADD AdditionalCol INT
GO
我们再来进行上述查询,看看返回的结果集
此时我们发现添加额外列后视图并未显示,当然数据也就不会显示了。此时我们在用视图查询之前进行刷新看看
USE AdventureWorks2012
GO
-- 查找原表
SELECT *
FROM HumanResources.[Shift]
GO
EXEC sp_refreshview 'view_limit'
IF EXISTS (SELECT * FROM sys.views WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[view_limit]'))
DROP VIEW [dbo].[view_limit]
GO
CREATE VIEW view_limit
AS
SELECT [SalesOrderID],[SalesOrderDetailID],[CarrierTrackingNumber] ,[OrderQty],sod.[ProductID],[SpecialOfferID],[UnitPrice],[UnitPriceDiscount] ,[LineTotal],[ReferenceOrderID] FROM Sales.SalesOrderDetail sod
INNER JOIN Production.TransactionHistory th ON sod.SalesOrderID = th.ReferenceOrderID
GO
解下来我们进行常规SQL查询和视图查询
USE AdventureWorks2012
GO
SELECT *
FROM dbo.view_limit
WHERE SalesOrderDetailID > 111111
GO
SELECT [SalesOrderID],[SalesOrderDetailID],[CarrierTrackingNumber] ,[OrderQty],sod.[ProductID],[SpecialOfferID],[UnitPrice],[UnitPriceDiscount] ,[LineTotal],[ReferenceOrderID] FROM Sales.SalesOrderDetail sod
INNER JOIN Production.TransactionHistory th ON sod.SalesOrderID = th.ReferenceOrderID
WHERE SalesOrderDetailID > 111111
GO
USE AdventureWorks2012
GO
SELECT v1.*
,th.[Quantity] FROM dbo.view_limit v1
INNER JOIN Production.TransactionHistory th ON v1.SalesOrderID = th.ReferenceOrderID
WHERE SalesOrderDetailID > 111111
GO
SELECT [SalesOrderID],[SalesOrderDetailID],[CarrierTrackingNumber] ,[OrderQty],sod.[ProductID],[SpecialOfferID],[UnitPrice],[UnitPriceDiscount] ,[LineTotal],[ReferenceOrderID] ,th.[Quantity] FROM Sales.SalesOrderDetail sod
INNER JOIN Production.TransactionHistory th ON sod.SalesOrderID = th.ReferenceOrderID
WHERE SalesOrderDetailID > 111111
GO
此时额外返回了Quantity列对视图再次进行JOIN,我们看看查询计划开销
USE AdventureWorks2012
GO
IF EXISTS (SELECT * FROM sys.objects
WHERE OBJECT_ID = OBJECT_ID(N'[dbo].[ViewTable]') AND TYPE IN (N'U'))
DROP TABLE [dbo].[ViewTable]
GO
CREATE TABLE ViewTable (ID1 INT, ID2 INT, SomeData VARCHAR(100))
INSERT INTO ViewTable (ID1,ID2,SomeData)
SELECT TOP 100000 ROW_NUMBER() OVER (ORDER BY o1.name),
ROW_NUMBER() OVER (ORDER BY o2.name),
o2.name
FROM sys.all_objects o1
CROSS JOIN sys.all_objects o2
GO
上述我们创建了测试的视图表ViewTable并插入了10万条测试数据,接下来我们对表建立索引。
USE AdventureWorks2012
GO
CREATE UNIQUE CLUSTERED INDEX [idx_original_table] ON dbo.ViewTable
(
ID1 ASC
)
接下来我们来创建视图并在视图上创建索引
USE AdventureWorks2012
GO
CREATE VIEW ViewLimit
WITH SCHEMABINDING
AS
SELECT ID1,ID2,SomeData
FROM dbo.ViewTable
GO
CREATE UNIQUE CLUSTERED INDEX [idx_view_table] ON [dbo].[ViewLimit]
(
ID2 ASC
)
GO
上述我们需要注意,当在视图上创建索引时必须指定WITH SCHAMABINDING,否则不允许在视图上创建索引。我们最后通过常规查询和视图查询来看看查询计划情况
USE AdventureWorks2012
GO
SELECT ID1,ID2,SomeData
FROM dbo.ViewTable
GO
SELECT ID1,ID2,SomeData
FROM dbo.ViewLimit
GO