我为视图中使用的查询创建了两个选项,返回我需要的结果。我需要重写任一选项,以便可以在索引视图中使用它。两者都失败了 在视图上创建唯一聚簇索引时。第一个由于LEFT OUTER JOIN而失败,第二个由于子查询而失败。我相信两者也会失败 自我加入。
找到Creating Indexed Views后,有一大堆无法使用的TSQL语法元素。其中:派生表,UNION,EXCEPT,INTERSECT,子查询, 外部或自联接,TOP,ORDER BY,DISTINCT,MAX ......
查询应为每个唯一CompanyID
获得最大Company
。还需要显示StatusName
表中的Statuses
,我只是添加它以防它影响
解决方案。它目前是INNER JOIN
,所以它不会导致创建索引的问题。
Companies
表的示例,其中所有3列均为INT
:
CompanyID Company Revision
1 1 1
2 1 2
3 2 1
4 2 2
查询应返回:
CompanyID Company Revision
2 1 2
4 2 2
以下是我创建的两个选项:
SELECT t1.CompanyID, t1.Company, t1.Revision, Statuses.StatusName
FROM dbo.Companies AS t1
LEFT OUTER JOIN dbo.Companies AS t2
ON t1.Company = t2.Company AND t1.CompanyID < t2.CompanyID
INNER JOIN dbo.Statuses
ON dbo.Statuses.StatusID = t1.StatusID
WHERE t2.Company IS NULL
另一个:
SELECT t1.CompanyID, t1.Company, t1.Revision, Statuses.StatusName
FROM dbo.Companies AS t1
INNER JOIN dbo.Statuses
ON dbo.Statuses.StatusID = t1.StatusID
WHERE t1.Company NOT IN (SELECT t2.Company from dbo.Companies AS t2 WHERE t1.CompanyID < t2.CompanyID)
所以,我的问题是,是否可以重写查询以在索引视图中使用?
我正在使用MS SQL Server 2008 R2和2005。
答案 0 :(得分:3)
为什么不尝试另一种方式,而不是创建排他性视图:
CREATE VIEW dbo.HighestCompany
AS
SELECT t1.CompanyID, t1.Company, t1.Revision, s.StatusName
FROM dbo.Companies AS t1
INNER JOIN (
SELECT Company, HighestCompany = MAX(CompanyID)
FROM dbo.Companies GROUP BY Company
) AS t2
ON t1.Company = t2.Company
AND t1.CompanyID = t2.HighestCompany -- not sure if CompanyID is unique
INNER JOIN dbo.Statuses AS s
ON s.StatusID = t1.StatusID;
您仍然无法在此处创建索引视图,但它可能比您当前拥有的版本稍微好一点(当然,取决于几个因素,包括公司和选择性的索引)。
除此之外,我认为要提高性能,您需要查看基表上的索引策略。为什么您的公司表允许多个公司使用相同的名称和不同的ID?也许这是问题的一部分,您应该将当前相关的公司存储在一个单独的表中。
你可以这样做(请记住我在这里猜测数据类型和最佳索引):
CREATE SCHEMA hold AUTHORIZATION dbo;
GO
CREATE SCHEMA cache AUTHORIZATION dbo;
GO
CREATE TABLE dbo.HighestCompany
(
CompanyID INT,
Company NVARCHAR(255) PRIMARY KEY,
Revision INT,
StatusName NVARCHAR(64)
);
GO
CREATE TABLE cache.HighestCompany
(
CompanyID INT,
Company NVARCHAR(255) PRIMARY KEY,
Revision INT,
StatusName NVARCHAR(64)
);
GO
现在,您经常认为需要刷新此数据,您可以运行执行以下操作的作业:
TRUNCATE TABLE cache.HighestCompany;
INSERT cache.HighestCompany(CompanyID, Company, Revision, StatusName)
SELECT t1.CompanyID, t1.Company, t1.Revision, s.StatusName
FROM dbo.Companies AS t1
INNER JOIN (
SELECT Company, HighestCompany = MAX(CompanyID)
FROM dbo.Companies GROUP BY Company
) AS t2
ON t1.Company = t2.Company
AND t1.CompanyID = t2.HighestCompany
INNER JOIN dbo.Statuses AS s
ON s.StatusID = t1.StatusID;
-- this is a fast, metadata operation that should result
-- in minimal blocking and disruption to end users:
BEGIN TRANSACTION;
ALTER SCHEMA hold TRANSFER dbo.HighestCompany;
ALTER SCHEMA dbo TRANSFER cache.HighestCompany;
ALTER SCHEME cache TRANSFER hold.HighestCompany;
COMMIT TRANSACTION;
如果你发现这些公司经常变化,或者数据真的需要高达一秒,这是不切实际的,你可以用@Dems建议的触发器做类似的事情。
答案 1 :(得分:1)
不幸的是,你不能。
您的查询不仅需要LEFT JOIN,而且要将同一个表格左键连接到自身。引用BooksOnline和你的问题...
The SELECT statement in the view cannot contain the following Transact-SQL syntax elements:
- Outer or self joins.
另一种选择可能是创建一个您通过触发器保持更新的真实映射表。正在Companies
更改创建/删除的记录,并且更新的记录更改为Statuses
。
同样,视图在线扩展到使用它们的查询中(除非您特别说明NOEXPAND
提示)。您是否检查过查询的执行计划,看看是否可以在基表上创建更合适的索引?
修改强>
另一种查询布局,就像一个选项......
;WITH
sequenced_companies
AS
(
SELECT
ROW_NUMBER() OVER (PARTITION BY Company ORDER BY CompanyID DESC) AS sequence_id,
*
FROM
dbo.companies
)
SELECT
*
FROM
sequenced_companies
INNER JOIN
dbo.statuses
ON statuses.StatusID = sequenced_companies.StatusID
WHERE
sequenced_companies.sequence_id = 1
使用(Company, CompanyID DESC)
上的索引,这应该非常快。 (虽然仍然不适合可索引的视图。)