Jer*_*sey 5 sql-server-2008 sql-server computed-column
我正在与程序员一起研究数据库解决方案。他们想要添加一个计算列来模拟旧查询、过程和系统的旧键,并为其编制索引。新密钥将是 GUIDS。
为此,他们希望为计算列创建一个函数,该函数创建一个值并将其持久化。它不会让他们保留该列。我对这个想法没有任何热情的模糊,我也无法在网上找到有关该技术的任何信息(它是一种技术吗?)。
我认为他们需要添加触发器。有没有人有任何想法?
该函数将按如下方式运行:
(SELECT [INT Identity field] FROM TABLE WHERE [GUID COLUMN] = @GUIDKEY
Run Code Online (Sandbox Code Playgroud)
它根据 GUID 返回一个 INT 标识字段。
这将在插入相关表时运行。因此,如果表一持有主键,则相关表二将更新(使用传入的 GUID)以从表一中获取键并将其插入到表二中。
仍然不明白为什么这需要是表中的一列,更不用说持久化的了。
为什么不创建一个表值函数,当(且仅当)查询实际需要它时交叉应用它?由于旧密钥永远不会改变,因此无论如何都不需要计算或持久化。
如果您真的希望旧密钥存在于多个地方(听起来不应该做出这种决定的人已经做出了这种决定),只需在触发器中进行查找并在写入时填充它. 那么它只是表中的一个静态列。
我仍然强烈推荐一个表值函数来促进这一点,这样你就可以以处理多行操作的方式编写触发器......而不必编写循环,或调用标量值函数对每一行再次重复。
只是为了展示这些东西到底有多相似(并询问“不喜欢它”的首席开发人员):
-- bad, slow, painful row-by-row
CREATE FUNCTION dbo.GetIDByGUID
(
@GuidKey uniqueidentifier
)
RETURNS int
AS
BEGIN
RETURN (SELECT $IDENTITY FROM dbo.tablename WHERE guid_column = @GuidKey);
END
GO
-- in the trigger:
UPDATE r SET oldkey = dbo.GetIDByGUID(i.guid_column)
FROM dbo.related AS r
INNER JOIN inserted AS i
ON r.guid_column = i.guid_column;
Run Code Online (Sandbox Code Playgroud)
现在,如果您有一个表值函数,代码非常相似,但您会发现多行操作的性能要好得多,而单行操作的性能几乎相同。
-- ah, much better
ALTER FUNCTION dbo.GetIDByGUID_TVF
(
@GuidKey uniqueidentifier
)
RETURNS TABLE
AS
RETURN (SELECT id = $IDENTITY FROM dbo.tablename WHERE guid_column = @GuidKey);
GO
-- in the trigger:
UPDATE r SET oldkey = f.id
FROM dbo.related AS r
INNER JOIN inserted AS i
ON r.guid_column = i.guid_column
CROSS APPLY dbo.GetIDByGUID_TVF(i.guid_column) AS f;
Run Code Online (Sandbox Code Playgroud)
我不确定为什么你认为你需要一个函数或一个计算列来做到这一点。您可以使用默认值向表中添加一个新列,然后根据需要对其进行索引。
CREATE TABLE dbo.whatever ( Id INT );
ALTER TABLE dbo.whatever
ADD YourMom UNIQUEIDENTIFIER
DEFAULT NEWSEQUENTIALID();
CREATE INDEX ix_whatever ON dbo.whatever (YourMom);
Run Code Online (Sandbox Code Playgroud)
既然你更新了你的问题,让我们来谈谈这是一个多么糟糕的想法。我将稍微简化一下这个例子。
CREATE TABLE dbo.whatever ( Id INT PRIMARY KEY);
CREATE TABLE dbo.ennui ( Id INT PRIMARY KEY, meh INT );
GO
CREATE FUNCTION dbo.BadIdea ( @notguido INT )
RETURNS INT
WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
AS
BEGIN
DECLARE @out INT;
SELECT @out = ( SELECT e.Id FROM dbo.ennui AS e WHERE e.meh = @notguido );
RETURN @out;
END;
GO
ALTER TABLE dbo.whatever ADD ishygddt AS dbo.BadIdea(Id)
/*Will fail*/
ALTER TABLE dbo.whatever ALTER COLUMN ishygddt ADD PERSISTED;
/*Will fail*/
CREATE INDEX ix_whatever ON dbo.whatever (ishygddt);
Run Code Online (Sandbox Code Playgroud)
如果它们执行数据访问,则尝试根据标量函数(即使是具有SCHEMABINDING的确定性函数)持久化计算列将失败。
消息 4934,级别 16,状态 3,第 23 行无法保留表 'whatever' 中的计算列 'ishygddt',因为该列执行用户或系统数据访问。
你也不能索引它:
消息 2709,级别 16,状态 1,第 25 行表 'dbo.whatever' 中的列 'ishygddt' 不能用于索引或统计信息或作为分区键,因为它执行用户或系统数据访问。
您还会遇到很多问题,因为该函数将逐行运行以检索数据,并将强制针对表的所有查询串行运行。
如果您正在修改函数引用的表中的数据,并从调用计算列中的函数的表中选择数据,您最终可能会遇到一些非常令人困惑的阻塞场景,即函数被阻止向查询返回数据在一张看似无关的桌子上。
这是一个坏主意。Aaron 在他的评论中给出了我认为最好的建议:
为什么不创建一个表值函数,当(且仅当)查询实际需要它时交叉应用它?由于旧密钥永远不会改变,因此无论如何都不需要计算或持久化。如果您真的希望旧密钥存在于多个地方,只需在触发器中进行查找即可。
归档时间: |
|
查看次数: |
4711 次 |
最近记录: |