是否可以为使用CDC功能的查询创建“索引视图”?

时间:2017-08-17 09:06:28

标签: tsql indexing view sql-server-2012 cdc

我尝试为cdc函数的结果创建索引视图。原始查询庞大而复杂。下面是生成相同错误的查询的简化版本:

SET NUMERIC_ROUNDABORT OFF;  
SET ANSI_PADDING, ANSI_WARNINGS, CONCAT_NULL_YIELDS_NULL, ARITHABORT,  
    QUOTED_IDENTIFIER, ANSI_NULLS ON;  
GO  
--Create view with schemabinding.  
IF OBJECT_ID ('dbo.view_Test', 'view') IS NOT NULL  
DROP VIEW dbo.view_Test;  
GO  
CREATE VIEW dbo.view_Test 
WITH SCHEMABINDING  
AS

SELECT 
kz.__$start_lsn,
    kz.__$seqval,
    kz.__$operation AS operation,
    kz.__$update_mask,
    kz.GUID,
    kz.typezalezh,
    kz.category,
    kz.zone,
    kz.area,
    kz.Volume
 FROM cdc.fn_cdc_get_all_changes_dbo_EXT_GeolObject_KategZalezh(sys.fn_cdc_get_min_lsn('dbo_EXT_GeolObject_KategZalezh'), sys.fn_cdc_get_max_lsn(), 'all') AS kz
 GO

此查询返回以下错误:

  

无法架构绑定视图'dbo.view_Test'。   'cdc.fn_cdc_get_all_changes_dbo_EXT_GeolObject_KategZalezh'不是   架构绑定。

我读了那个

  

如果要在视图上创建索引,或者要保留视图   在这两种情况下,一旦定义了视图,就会生成基表模式   您必须使用“WITH SCHEMABINDING”子句将视图绑定到   基表的模式

在原始查询中我使用dbocdc架构,我只使用cdc架构。但我想在dbo dchema创建视图。 此外,我正在使用CDC功能,而不是像微软推荐的那样直接使用cdc表。

我在阅读创建索引视图时需要考虑的一些事项:

  • 即使您使用架构绑定,也无法在视图中使用外部联接创建索引
  • 即使您使用架构绑定,也无法在视图中使用外部联接创建索引
  • 在模式绑定时,不能在视图的select语句中使用'*'。
  • 如果视图引用任何非确定性函数,您将无法在视图上创建聚簇索引。
  • 使用架构绑定时,不能使用聚合函数。
  • 您无法迁移架构绑定视图的基表。

据我了解,我的查询符合此规则。但我不确定CDC功能是确定性还是不确定性。

是否可以为使用CDC功能的查询创建“索引视图”?

1 个答案:

答案 0 :(得分:1)

不,CDC功能不是“架构绑定”,因此依赖于它的视图根本无法编入索引。相反,您可以创建一个表并定期从函数中填充它。

假设您有启用CDC的表“testdb.dbo.Customers_for_cdc_test”。您可以通过代码实现CDC功能:

use testdb
go
select top (0) *
  into dbo.SOURCE_NAME_changes
  from cdc.fn_cdc_get_all_changes_dbo_Customers_for_CDC_test
       (
         sys.fn_cdc_get_min_lsn('dbo_Customers_for_cdc_test')
       , sys.fn_cdc_get_max_lsn()
       , N'all'
       ) as src
;
create index IX__dbo__SOURCE_NAME_changes
  on dbo.SOURCE_NAME_changes
  (
    __$start_lsn asc
  )
;
-- Other needed indices can be here.
go

表填充可以作为作业实现。设置定期启动的作业计划。作业本身可能只包含一个调用填充程序的步骤

use testdb
go
exec dbo.sp_append_new_SOURCE_NAME_changes

“dbo.sp_append_new_SOURCE_NAME_changes”是

use testdb
go
create procedure dbo.sp_append_new_SOURCE_NAME_changes
  as
  begin
    set nocount on
    ;
    declare @max_old_lsn    as binary(10) 
          , @min_old_lsn    as binary(10)
          , @min_active_lsn as binary(10) = sys.fn_cdc_get_min_lsn('dbo_Customers_for_CDC_test')
          , @max_active_lsn as binary(10) = sys.fn_cdc_get_max_lsn()
    ;
    select @max_old_lsn = coalesce(max(__$start_lsn) ,cast(0 as binary(10)))
         , @min_old_lsn = coalesce(min(__$start_lsn) ,cast(0 as binary(10)))
      from dbo.SOURCE_NAME_changes
    ;
    if (@min_old_lsn < @min_active_lsn
    ) begin
        delete from dbo.SOURCE_NAME_changes
          where __$start_lsn < @min_active_lsn
        ;
      end
    if (@max_old_lsn < @max_active_lsn
    ) begin
        declare @min_lsn as binary(10) = iif(@min_active_lsn < @max_old_lsn ,@max_old_lsn ,@min_active_lsn) -- Speed up
        ;
        insert into dbo.SOURCE_NAME_changes
          --(COLUMN_LIST)
          select * --(COLUMN_LIST)
            from cdc.fn_cdc_get_all_changes_dbo_Customers_for_CDC_test
                 (
                   @min_lsn
                 , @max_active_lsn
                 , N'all'
                 ) as src
            where src.__$start_lsn > @max_old_lsn -- Because the max old lsn is already in.
          ;
      end
  end
go