引用Erik Darling 在我最喜欢的 SQL Server 大师 Brent Ozar 的网站上发表的这篇博客文章:
当您单独从该表中进行选择时,它会显示“ CouldNotGenerateValidParallelPlan ”。
但是,当您将该表连接到另一个没有调用标量 UDF 的检查约束/计算列的表时,查询与“ Good Enough Plan Found ”并行
USE tempdb;
SET NOCOUNT ON;
SELECT TOP 10000
ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL )) AS ID, DATEADD(MINUTE, m.message_id, SYSDATETIME()) AS SomeDate
INTO dbo.constraint_test_1
FROM sys.messages AS m, sys.messages AS m2;
GO
SELECT TOP 10000
ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL )) AS ID, DATEADD(MINUTE, m.message_id, SYSDATETIME()) AS SomeDate
INTO dbo.constraint_test_2 …Run Code Online (Sandbox Code Playgroud) 我需要一个计算列来解决隐式转换问题。我有一个声明为 VARCHAR 的列,它应该只存储整数,但偶尔会被带有字符串的第三方应用程序错误填充,因此该列需要保持原样。
该表通常连接到一个将该值存储为 INT 的表。我定义了一个 PERSISTED 计算列,用于将该 VARCHAR 转换为 INT:
[iOrderNumber] AS (CONVERT([int],
case
when [ordernumber] like '#%' then (-99) when isnumeric([ordernumber])=(0) then (-99)
when CONVERT([bigint],[ordernumber],(0))>(2147483647) then (-99)
else [ordernumber]
end,(0))) PERSISTED NOT NULL
Run Code Online (Sandbox Code Playgroud)
使用计算列上的适当索引,现在可以连接到 INT 列的查询的性能显着提高。但是,即使在更新表而不是读取表时发生转换,执行计划仍会显示隐式转换警告。
我尝试在计算列定义中使用 UDF 来消除警告(我找到了一篇建议这样做的博客文章),但随后我的查询的执行时间更长,并且使用了更多的 CPU,尽管逻辑读取保持不变。但是 UDF 确实消除了警告。
除了错误之外,还有其他理由考虑警告吗?是否有理由将优化器对使用 UDF 定义的持久计算列的处理视为错误?
更重要的是,有没有办法摆脱警告,而不会招致 UDF 解决方案的性能损失?
我考虑使用触发器和包含数据的 VARCHAR 和 INT 版本的转换表,而不是使用计算列,但这似乎是很多不必要的开销。
我road_condition在Oracle 12c 中有一张表:
create table road_condition (
cond_id number(5,0),
road_id number(5,0),
cond_date date,
condition number(5,0)
);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (1,100,to_date('01-NOV-84','DD-MON-RR'),18);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (2,100,to_date('01-JAN-09','DD-MON-RR'),6);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (3,100,to_date('19-JUN-12','DD-MON-RR'),4);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (4,100,to_date('29-APR-15','DD-MON-RR'),4);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (5,200,to_date('29-APR-92','DD-MON-RR'),20);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (6,200,to_date('05-APR-17','DD-MON-RR'),3);
commit;
Run Code Online (Sandbox Code Playgroud)
结果表数据:
COND_ID ROAD_ID COND_DAT CONDITION
------- ------- -------- ---------
1 100 84-11-01 18
2 100 09-01-01 6
3 100 12-06-19 4
4 100 …Run Code Online (Sandbox Code Playgroud) 我正在处理一个项目,其中数据模型中的许多实体没有名称列,而是需要从多个列的串联中构造“名称”。最初我认为这可能是计算列的一个很好的用例,因为它允许我在数据库中定义这个逻辑,并且只定义一次。
但是,对于完全规范化的数据模型,计算列通常需要来自其他表的值。查询其他表可以通过 UDF 来完成,但我在几个地方读到在计算列中使用 UDF 会阻止并行执行(请参阅此处)。
我可以使用视图来处理这些名称的格式,但只想定义一次逻辑,如果逻辑在视图中,它可能会导致嵌套视图,这也会导致性能问题。
我希望有人知道如何在数据库中只定义一次这种格式逻辑而不导致性能问题。
我看了一下这个问题:
表达式中的类型转换可能会影响查询计划选择中的“CardinalityEstimate”?
但这与整理有关,而不是与计算列有关。
我在下面的查询中使用了以下表定义,它给了我一个查询提示
表达式中的类型转换 (CONVERT(varchar(10),[t].[FLTCD_FLT_DATE],112)) 可能会影响查询计划选择中的“CardinalityEstimate”
请注意计算列 flightReference
CREATE TABLE [dbo].[repl_Transportation] (
[FLIGHT#] INT NOT NULL,
[FLTCD_FLT_DATE] DATETIME NULL,
[FLTCD_DEP_GATE] CHAR(3) NULL,
[FLTCD_ARR_GATE] CHAR(3) NULL,
[FLTCD_SEQUENCE] CHAR(1) NULL,
[DIRECTION] CHAR(1) NULL,
[PNR_NUMBERS] VARCHAR(70) NULL,
[HK] NUMERIC(3,0) NULL,
[Create_Date] DATETIME NOT NULL,
[Modify_Date] DATETIME NULL,
[flightReference] AS (substring(((CONVERT([varchar](10),[FLTCD_FLT_DATE],
(112))+[FLTCD_DEP_GATE])+[FLTCD_ARR_GATE])+[FLTCD_SEQUENCE],(3),(13))) PERSISTED,
CONSTRAINT [PK_FLIGHT#] PRIMARY KEY CLUSTERED ([FLIGHT#] asc))
IF OBJECT_ID('[dbo].[repl_Transportation_Details]') IS NOT NULL
DROP TABLE [dbo].[repl_Transportation_Details]
GO
CREATE TABLE [dbo].[repl_Transportation_Details] (
[FLT_LEG_ID] INT NOT NULL,
[FLIGHT#] INT NOT NULL,
[LEG_NO] TINYINT …Run Code Online (Sandbox Code Playgroud) sql-server optimization sql-server-2016 computed-column cardinality-estimates
我正在与程序员一起研究数据库解决方案。他们想要添加一个计算列来模拟旧查询、过程和系统的旧键,并为其编制索引。新密钥将是 GUIDS。
为此,他们希望为计算列创建一个函数,该函数创建一个值并将其持久化。它不会让他们保留该列。我对这个想法没有任何热情的模糊,我也无法在网上找到有关该技术的任何信息(它是一种技术吗?)。
我认为他们需要添加触发器。有没有人有任何想法?
该函数将按如下方式运行:
(SELECT [INT Identity field] FROM TABLE WHERE [GUID COLUMN] = @GUIDKEY
Run Code Online (Sandbox Code Playgroud)
它根据 GUID 返回一个 INT 标识字段。
这将在插入相关表时运行。因此,如果表一持有主键,则相关表二将更新(使用传入的 GUID)以从表一中获取键并将其插入到表二中。
我正在尝试存储和索引 IP 地址。我从一个简单而愚蠢的表格开始:
CREATE TABLE [dbo].[IP_addresses](
[IP_as_text] [char](16) NOT NULL,
[IP] AS ([dbo].[fnBinaryIPv4]([IP_as_text]))
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
哪里fnBinaryIPv4来自/sf/ask/96988671/。
CREATE FUNCTION dbo.fnBinaryIPv4(@ip AS VARCHAR(15)) RETURNS BINARY(4)
AS
BEGIN
DECLARE @bin AS BINARY(4)
SELECT @bin = CAST( CAST( PARSENAME( @ip, 4 ) AS INTEGER) AS BINARY(1))
+ CAST( CAST( PARSENAME( @ip, 3 ) AS INTEGER) AS BINARY(1))
+ CAST( CAST( PARSENAME( @ip, 2 ) AS INTEGER) AS BINARY(1))
+ CAST( CAST( PARSENAME( @ip, 1 ) AS INTEGER) AS BINARY(1)) …Run Code Online (Sandbox Code Playgroud) 我有许多列存储数据,这些数据可能包含一些用于格式化/分组的额外字符。想想电话号码和车牌号码等数据中的空白和破折号。
查询时,我们无法确定这些破折号是否存在以及在哪里存在,因此我们需要将它们从列中剥离。在查询时这样做对性能不利,所以我想为剥离的列创建一个计算列并在其上放置一个索引。
-- trimming the length down to 50 characters
-- which is the length of the original field
ALTER TABLE foo
ADD search_license_plate AS (LEFT(REPLACE(license_plate, '-', ''), 50));
CREATE INDEX ix_foo_search_license_plate ON foo(search_license_plate);
Run Code Online (Sandbox Code Playgroud)
这些计算列总是精确的,因此它们不需要因为缺乏精度而被持久化。
数据通常只输入一次并且很少被更改。从不大量使用,所以我不太关心持久化列的任何性能影响。
此外,计算列永远不会从查询中返回;它只会在查询条件中使用,通常
SELECT
foo.id,
foo.license_plate
FROM foo
WHERE foo.search_license_plate LIKE '%bar%';
Run Code Online (Sandbox Code Playgroud)
...虽然我不能保证SELECT *这些表上没有完成。
是否需要保留这些列?
我有一个带有复杂列的查询,我想在另一列中使用此列结果,例如:
SELECT ( /* Complex query */ ) as myValue, if( myValue > 10, "OK" , "" ) from table;
Run Code Online (Sandbox Code Playgroud)
但他的查询返回一个错误:
Error Code: 1054. Unknown column 'myValue' in 'field list
Run Code Online (Sandbox Code Playgroud)
如何重用已计算的字段?
我有一张桌子,Id作为主键。
create table Anything
(
Id bigint not null primary key identity(1, 1)
)
Run Code Online (Sandbox Code Playgroud)
当我查看 中的这张表时Object Explorer,我当然会看到这张图片:
正如你所看到的,列Id是不为空。
然后我在这个虚拟表上创建一个虚拟视图:
create view IdIsTwoView
as
select
Id,
(
case
when Id = 2
then cast(1 as bit)
else cast(0 as bit)
end
) as IdIsTwo
from Anything
Run Code Online (Sandbox Code Playgroud)
但这一次,在对象资源管理器中,我看到了这个结果:
如您所见,尽管我的case子句包罗万象,涵盖了所有记录的 100%,并且对所有记录都有答案,但它可以为空。
为什么 SQL Server 有这种奇怪的行为?我如何强制它不为 null?
PS我们有一个动态生成代码的基础设施,这种行为给我们带来了麻烦,我们必须手动将bool?C# 中的所有类型更改为bool.
computed-column ×10
sql-server ×8
date-math ×1
functions ×1
index ×1
mysql ×1
null ×1
optimization ×1
oracle ×1
oracle-12c ×1
parallelism ×1
view ×1
warning ×1