我为 View 中使用的查询创建了两个选项,它们返回我需要的结果。我需要重写任一选项,以便它可以在 索引 View 中使用。都失败了 在 View 上创建唯一聚集索引 时。第一个因 LEFT OUTER JOIN 而失败,第二个因子查询而失败。我相信两者都会失败,因为 自连接。
找到Creating Indexed Views后, 有大量不能使用的 TSQL 语法元素。其中:派生表、UNION、EXCEPT、INTERSECT、子查询、 外连接或自连接、TOP、ORDER BY、DISTINCT、MAX……
查询应该为每个唯一的 Company
获取最大的 CompanyID
。 Statuses
表中的 StatusName
也需要显示,我只是添加它以防它影响
解决方案。它目前是一个 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)
所以,我的问题是,是否可以重写任何一个查询以在索引 View 中使用?
我使用的是 MS SQL Server 2008 R2 和 2005。
最佳答案
为什么不尝试另一种方式,而不是创建排他性 View :
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;
您仍然无法为此创建索引 View ,但它可能比您当前拥有的版本要好一些(当然,取决于几个因素,包括公司索引和选择性)。
除此之外,我认为要提高性能,您需要查看基表的索引策略。为什么您的 Companies 表允许多个公司具有相同的名称和不同的 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 建议的那样使用触发器做类似的事情。
关于sql - 由于 LEFT JOIN 或子查询,无法在 View 上创建 CLUSTERED INDEX,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9669481/