从计算列引用另一个表

Dan*_*anO 5 sql-server computed-column

我正在处理一个项目,其中数据模型中的许多实体没有名称列,而是需要从多个列的串联中构造“名称”。最初我认为这可能是计算列的一个很好的用例,因为它允许我在数据库中定义这个逻辑,并且只定义一次。

但是,对于完全规范化的数据模型,计算列通常需要来自其他表的值。查询其他表可以通过 UDF 来完成,但我在几个地方读到在计算列中使用 UDF 会阻止并行执行(请参阅此处)。

我可以使用视图来处理这些名称的格式,但只想定义一次逻辑,如果逻辑在视图中,它可能会导致嵌套视图,这也会导致性能问题。

我希望有人知道如何在数据库中只定义一次这种格式逻辑而不导致性能问题。

ype*_*eᵀᴹ 6

您可以为此使用索引视图。假设关系是简单(外键)关系,我不明白为什么这会导致任何问题。

简单的例子,在 dbfiddle.uk 中测试:

create table game
( game_id int not null primary key,
  game_name varchar(100) not null  
) ;

create table area
( area_id int not null primary key,
  area_name varchar(100) not null 
) ;

create table player
( player_id int not null primary key,
  player_name varchar(100) not null 
) ;
Run Code Online (Sandbox Code Playgroud)
insert into game
values
  (1, 'chess'),
  (2, 'go'),
  (3, 'reversi'),
  (4, 'backgammon'),
  (5, 'hex'),
  (6, 'havannah'),
  (7, 'pacman') ;

insert into area
values
  (11, 'usa'),
  (12, 'russia'),
  (13, 'greece'),
  (14, 'uk'),
  (15, 'france'),
  (16, 'hungary'),
  (17, 'ukraine'),
  (18, 'belgium'),
  (19, 'canada'),
  (20, 'new zealand')  ;

insert into player
values
  (7, 'John'),
  (8, 'Mary'),
  (9, 'Alex'),
  (10, 'Anna'),
  (11, 'Fred'),
  (12, 'Fay') ;
Run Code Online (Sandbox Code Playgroud)
23行受影响
create table playground
( playground_id int not null identity primary key,
  game_id int not null references game,
  area_id int not null references area,
  player_id int not null  references player,
  various_stuff varchar(100) null default 'abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz',
  constraint playground_uq 
    unique (game_id, area_id, player_id)
) ;
Run Code Online (Sandbox Code Playgroud)
create view dbo.play 
  (game_id, area_id, player_id, name)
WITH SCHEMABINDING 
as
select 
    pg.game_id,
    pg.area_id,
    pg.player_id,
    name = g.game_name + '-' + a.area_name + '-' + p.player_name  
from dbo.playground as pg 
  join dbo.game   as g on g.game_id   = pg.game_id 
  join dbo.area   as a on a.area_id   = pg.area_id
  join dbo.player as p on p.player_id = pg.player_id ;
Run Code Online (Sandbox Code Playgroud)
 -- create an index on the view  
create unique clustered index play_cix   
    on play (game_id, area_id, player_id) ;
Run Code Online (Sandbox Code Playgroud)
insert into playground
  (game_id, area_id, player_id)
select game_id, area_id, player_id
from game, area, player ;
Run Code Online (Sandbox Code Playgroud)
420 行受影响
--------------------------------------------------------------------------------
-- Or use XML to see the visual representation, thanks to Justin Pealing and
-- his library: https://github.com/JustinPealing/html-query-plan
--------------------------------------------------------------------------------
set statistics xml on;

select -- top (10) 
   game_id, area_id, player_id, name 
from play 
   WITH (NOEXPAND)            -- Hint used because we are in Express edition
  ;
set statistics xml off;
Run Code Online (Sandbox Code Playgroud)
游戏 ID | 区域 ID | 玩家 ID | 姓名                       
------: | ------: | --------: | :--------------------------
      1 | 11 | 11 7 | 国际象棋美国约翰             
      1 | 11 | 11 8 | 玛丽国际象棋             

   --- 省略了几百行

  7 |      20 |        11 | pacman-new zealand-Fred    
  7 |      20 |        12 | pacman-new zealand-Fay     
Run Code Online (Sandbox Code Playgroud) | Microsoft SQL Server 2005 XML 展示计划 | : | <ShowPlanXML xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan" Version="1.8" Build="14.0.3015.40"><BatchSequence><Batch><Statements><StmtSimple StatementText="选择 -- 顶部 (10) game_id、area_id、player_id、姓名 from play WITH (NOEXPAND)" StatementId="1" StatementCompId="2" StatementType="SELECT" RetrievedFromCache= “真”StatementSubTreeCost =“0.00522548”StatementEstRows =“420”SecurityPolicyApplied =“假”StatementOptmLevel =“TRIVIAL”QueryHash =“0xBA9BAED6D700FD27”QueryPlanHash =“0xE0086846AA2CCE7F”CardinalityEstimationModelVersion =“140”> <StatementSetOptions QUOTED_IDENTIFI ER=“真” ARITHABORT=“真” " CONCAT_NULL_YIELDS_NULL="true" ANSI_NULLS="true" ANSI_PADDING="true" ANSI_WARNINGS="true" NUMERIC_ROUNDABORT="false"></StatementSetOptions><QueryPlan DegreeOfParallelism="0" NonParallelPlanReason="NoParallelPlansInDesktopOrExpressEdition" CachedPlanSize="16" CompileTime= "0" CompileCPU="0" CompileMemory="88"><MemoryGrantInfo SerialRequiredMemory="0" SerialDesiredMemory="0"></MemoryGrantInfo><OptimizerHardwareDependentProperties EstimatedAvailableMemoryGrant="419378" EstimatedPagesCached="26211" EstimatedAvailableDegreeOfParallelism="1" MaxCompileMemory= "2073864"></OptimizerHardwareDependentProperties><TraceFlags IsCompileTime="1"><TraceFlag Value="8017" Scope="Global"></TraceFlag></TraceFlags><TraceFlags IsCompileTime="0"><TraceFlag Value=" 8017" Scope="Global"></TraceFlag></TraceFlags><QueryTimeStats ElapsedTime="15" CpuTime="15"></QueryTimeStats><RelOp NodeId="0" PhysicalOp="聚集索引扫描" LogicalOp="聚集索引扫描”EstimateRows =“420”EstimatedRowsRead =“420”EstimateIO =“0.00460648”EstimateCPU =“0.000619”AvgRowSize =“174”EstimatedTotalSubtreeCost =“0.

dbfiddle在这里

以及从视图中选择的查询的执行计划,显示使用了物化视图上的聚集索引:

执行计划


小智 0

我认为这个问题没有一个正确的答案。正如一些评论中所暗示的,您几乎总是会在性能和复杂性/可维护性之间进行一些权衡。

我们遇到过类似的情况,无法选择使用视图,因此我们在计算列中选择了 UDF。我们遇到的问题是您无法保留该列,如果函数引用其他对象(例如表),则需要对其进行索引。

您似乎了解可用的选项,并且只需要为您和您的利益相关者找到最佳解决方案。