由于LEFT JOIN或子查询,无法在视图上创建CLUSTERED INDEX

njb*_*njb 3 sql t-sql sql-server clustered-index

我为视图中使用的查询创建了两个选项,这些选项返回我需要的结果。我需要重写任一选项,以便可以在索引视图中使用它。在视图上创建唯一的聚集索引时,两者均失败。第一个由于LEFT OUTER JOIN而失败,第二个由于子查询而失败。我相信两者都会由于自我加入而失败。

找到“ 创建索引视图”之后,有一大堆无法使用的TSQL语法元素。其中:派生表,UNION,EXCEPT,INTERSECT,子查询,外部或自我联接,TOP,ORDER BY,DISTINCT,MAX ...

CompanyID对于每个唯一查询,查询都应为最大Company。将StatusNameStatuses表还需要显示,而我只补充说,在情况下,它会影响解决方案。当前是INNER JOIN,因此创建索引不会引起问题。

Companies表的示例,所有3列均为INT

CompanyID Company Revision
1         1       1
2         1       2
3         2       1
4         2       2
Run Code Online (Sandbox Code Playgroud)

查询应返回:

CompanyID Company Revision
2         1       2
4         2       2
Run Code Online (Sandbox Code Playgroud)

这是我创建的两个选项:

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
Run Code Online (Sandbox Code Playgroud)

和另一个:

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)
Run Code Online (Sandbox Code Playgroud)

因此,我的问题是,是否可以重写任一查询以在索引视图中使用?

我正在使用MS SQL Server 2008 R2和2005。

Aar*_*and 5

与其创建排斥视图,不如尝试其他方法:

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;
Run Code Online (Sandbox Code Playgroud)

您仍然无法在此上创建索引视图,但是它可能比您当前使用的版本好一些(当然,这取决于多个因素,当然包括公司索引和选择性)。

除此之外,我认为要提高性能,您需要查看基表上的索引策略。为什么您的“公司”表允许多个具有相同名称和不同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
Run Code Online (Sandbox Code Playgroud)

现在,尽管您经常认为需要刷新此数据,但是您可以运行执行以下操作的作业:

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;
Run Code Online (Sandbox Code Playgroud)

如果您发现公司变化如此频繁,或者确实需要更新数据以至于这是不切实际的,则可以使用@Dems建议的触发器来执行类似的操作。