【问题标题】:Persisted computed column with subquery带有子查询的持久计算列
【发布时间】:2011-07-13 15:40:10
【问题描述】:

我有这样的事情

create function Answers_Index(@id int, @questionID int)
returns int
as begin
    return (select count([ID]) from [Answers] where [ID] < @id and [ID_Question] = @questionID)
end
go

create table Answers
(
    [ID] int not null identity(1, 1),
    [ID_Question] int not null,
    [Text] nvarchar(100) not null,
    [Index] as [dbo].[Answers_Index]([ID], [ID_Question]),
)
go

insert into Answers ([ID_Question], [Text]) values
    (1, '1: first'),
    (2, '2: first'),
    (1, '1: second'),
    (2, '2: second'),
    (2, '2: third')

select * from [Answers]

效果很好,但它往往会降低查询速度。如何使列Index 保持不变?我试过以下:

create table Answers
(
    [ID] int not null identity(1, 1),
    [ID_Question] int not null,
    [Text] nvarchar(100) not null,
)
go

create function Answers_Index(@id int, @questionID int)
returns int
with schemabinding
as begin
    return (select count([ID]) from [dbo].[Answers] where [ID] < @id and [ID_Question] = @questionID)
end
go

alter table Answers add [Index] as [dbo].[Answers_Index]([ID], [ID_Question]) persisted
go

insert into Answers ([ID_Question], [Text]) values
    (1, '1: first'),
    (2, '2: first'),
    (1, '1: second'),
    (2, '2: second'),
    (2, '2: third')

select * from [Answers]

但这会引发以下错误:Computed column 'Index' in table 'Answers' cannot be persisted because the column does user or system data access. 或者我应该忘记它并使用[Index] int not null default(0) 并将其填充到on insert 触发器中?

编辑:谢谢,最终解决方案:

create trigger [TRG_Answers_Insert]
on [Answers]
for insert, update
as
    update [Answers] set [Index] = (select count([ID]) from [Answers] where [ID] < a.[ID] and [ID_Question] = a.[ID_Question])
        from [Answers] a 
        inner join [inserted] i on a.ID = i.ID      
go

【问题讨论】:

  • 老实说,我不完全确定我理解您要解决的问题 - 选择查询慢吗?它不会触及您的“索引”列,所以我看不出这有什么关系 - 尽管您可能想要添加一个或两个索引......

标签: sql-server calculated-columns


【解决方案1】:

您可以将该列更改为普通列,然后在使用触发器插入/更新该行时更新其值。

create table Answers
(
[ID] int not null identity(1, 1),
[ID_Question] int not null,
[Text] nvarchar(100) not null,
[Index] Int null
)

CREATE TRIGGER trgAnswersIU
ON Answers
FOR INSERT,UPDATE
AS 
   DECLARE @id int
   DECLARE @questionID int
   SELECT @id = inserted.ID, @questionID = inserted.ID_question


  UPDATE Answer a
  SET Index = (select count([ID]) from [Answers] where [ID] < @id and [ID_Question] = @questionID)
  WHERE a.ID = @id AND a.ID_question = @questionID

GO

NB* 这并不完全正确,因为它不能在 UPDATE 上正常工作,因为我们没有“插入”表来引用来获取 ID 和 questionid。有办法解决这个问题,但我现在不记得了:(

Checkout this for more info

【讨论】:

  • 这不考虑多行 INSERT/UPDATE。
【解决方案2】:

计算列仅存储要执行的计算公式。这就是为什么从表中查询计算列时速度会变慢的原因。如果您想将值保存到实际的表列中,那么使用触发器是正确的。

【讨论】:

  • 持久化计算列应该保存计算值(它们通过模式绑定来检测需要更新)...问题是计算列的一般限制(持久计算列更是如此) .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 2019-04-02
  • 1970-01-01
  • 1970-01-01
  • 2022-01-02
相关资源
最近更新 更多