【问题标题】:How to get rid of timeout error when using mssql hierarchy check constrint使用 mssql 层次结构检查约束时如何摆脱超时错误
【发布时间】:2016-12-02 14:37:17
【问题描述】:

我正在创建 sqlhirercky 表

这是我的代码;

约束函数代码

                    alter Function Accounts.Types_Sub_Check_fn (@ID uniqueidentifier, @Sub Uniqueidentifier) returns int
                    begin
                    --declare @id uniqueidentifier = '8c7d4151-246c-476c-adf6-964ca9afdd3c' declare @sub uniqueidentifier = '47c2b6da-25fc-4921-adfa-b1f635bddde6'
                    declare @a int
                    declare @b int =(iif(@ID=@SUB,2,0))

                    ;with cte(id, lvl) as
                      (
                        select f.sub,
                               1
                        from Accounts.Types as f
                        where f.id = @id
                        union all
                        select f.sub,
                               lvl + 1
                        from Accounts.Types as f
                          inner join cte as c
                            on f.id = c.id
                      )
                      select @a = (select count (*)
                                     from cte
                                     where id =@sub) + @b


                      option (maxrecursion 0)


                        return @a
                    end
                    go

表格代码

   create Table Accounts.Types
                        (
                        ID uniqueidentifier  not null CONSTRAINT DF_Accounts_Types_ID DEFAULT newid() CONSTRAINT PK_Accounts_Types_ID PRIMARY KEY NONCLUSTERED (ID) ,
                        Name varchar(200) not null CONSTRAINT UQ_Accounts_Types_NAME UNIQUE (NAME), 
                        Sub uniqueidentifier CONSTRAINT FK_Accounts_Types_Sub Foreign key references Accounts.Types ,
                        Ctype uniqueidentifier CONSTRAINT FK_Accounts_Types_Ctype Foreign key references Accounts.Types ,
                        insert_time datetime not null CONSTRAINT DF_Accounts_Types_Insert_Time DEFAULT getdate() ,
                        insert_user uniqueidentifier CONSTRAINT DF_Accounts_Types_Insert_User DEFAULT'9EC66F53-9233-4A6C-8933-F8417D2BB5A9'  ,
                        ts timestamp,
                        INDEX IX_Accounts_Types_NAME#ASC CLUSTERED (Name ASC),
                        Constraint Check_Accounts_Types_Sub check (Accounts.Types_Sub_Check_fn(ID,Sub)<=1)
                        )
                        go

如果尝试将其插入作为父级(在子列中),此函数将给出 2 作为结果

如果它已经是一个孩子,它会给出 1,它试图作为它的父母插入

创建 Check 约束是为了检查任何 id 的父(子列)是否不应该是它的子或孙子, 并且它本身不能是它的父级

当我尝试插入与检查约束不匹配的数据时,它卡住了,并给出了超时错误,

例如:

   insert into Accounts.Types (ID, Name, Sub)
   values ('607936b9-6f95-4989-8ebe-87a08807f43e','LLL','607936b9-6f95-4989-8ebe-87a08807f43e')

这会超时

谁能帮帮我,我需要摆脱超时错误;只得到约束错误

【问题讨论】:

  • 看起来您正在通过构建 CSV 字符串然后对其执行 LIKE 来检查父/子/自我关系。您可能可以直接使用递归 CTE 检查关系,而无需构建 CSV 字符串。
  • 您是否排除了通过 hierarchyid 数据类型使用构建来支持建模层次结构?
  • 如果在“树”中创建循环,则 CTE 将运行一段时间。 This 答案显示了一种在检测到循环时终止递归的方法。

标签: sql-server tsql


【解决方案1】:

简单的问题 - 当您的 ID 和 Sub 是相同的值并且您不限制 maxrecursion 或 lvl 时,您的递归何时结束?绝不。它永远不会结束。

values ('607936b9-6f95-4989-8ebe-87a08807f43e','LLL','607936b9-6f95-4989-8ebe-87a08807f43e')

您必须删除 ID = Sub 的行或添加 maxrecursion 或添加级别限制或规范化您的表。

【讨论】:

  • 你是对的,它永远不会结束;因为插入后检查约束检查
  • 刚刚换了行-------------------------- ------------------------------------------------------- union all select f.sub, -------------------------------------------------- - - - - - - - - 至 - - - - - - - - - - - - - - - - - -------------------------------------------------- -------------------------联合所有选择 iif(f.Sub = @sub, Null, f.sub), ------ -------------------------------------------------- ---------- 使当前更新记录的子列为空以结束循环。
【解决方案2】:
            alter Function Accounts.Types_Sub_Check_fn (@ID uniqueidentifier, @Sub Uniqueidentifier) returns int
                    begin
                    --declare @id uniqueidentifier = '00279c6b-df00-4144-810d-571fdb1c5109' declare @sub uniqueidentifier = 'bc887e7b-36d2-4ece-8ec1-720dc81a9de4'
                    declare @a int = 0
                    declare @b int =(iif(@ID=@SUB,2,0))
                    if @ID <> @sub
                    begin
                    ;with cte(id, lvl) as
                      (
                        select f.Sub ,
                               1
                        from Accounts.Types as f
                        where f.id = @sub 
                        union all
                        select  iif(f.Sub = @sub, Null, f.sub),
                               lvl + 1
                        from Accounts.Types as f
                          inner join cte as c
                            on f.id = c.id 
                      )

                      select @a = (select count (*)
                                     from cte
                                     where id =@id) 

        option (maxrecursion 0);


                      end
                    --  select @a + @b


                        return @a + @b
                    end
                    go

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    相关资源
    最近更新 更多