最近偶然发现以下问题:更改元数据会更改查询输出。
\n\n以下是如何获取它。
\n\nCREATE TABLE [dbo].[prod]\n(\n[ID] [tinyint] NOT NULL,\n[values] [tinyint] NOT NULL\n) \nGO\nRun Code Online (Sandbox Code Playgroud)\n\n以下查询始终返回 \xe2\x80\x98This is the end\xe2\x80\x99 (始终引发错误)。此外,过滤器应该是某种随机生成器。
\n\nBEGIN TRY\nSELECT [id] FROM \n (\n SELECT [id] as [id]\n FROM dbo.prod\n WHERE ([id]=1/0)\n ) t1\nWHERE\n-- Random generator 1 always returns false\n(FLOOR(RAND()*(1))=1)\n-- Random generator 2 does not always return false\n/*\nSUBSTRING( cast(NEWID() as varchar(max)), 1, 1)\nIN ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F')\n*/\n-- Random generator 3 does not always return …Run Code Online (Sandbox Code Playgroud) 我正在尝试修改共享开发数据库,供开发团队用于应用程序开发/测试。
大多数集体工作(表名、视图等)都存储在公共环境中模式中,但我已经为每个用户设置了模式以用作临时空间。然而,真正的目标是用户使用其架构中的对象(如果存在),然后依赖其他对象,就像今天使用 search_path 的方式一样。
用一个例子可能会更好地描述这一点。假设团队正在开发一个汽车维修应用程序的数据库,其中包含一些表和视图:
public.automobiles
public.parts
public.inventory
public.mechanics
public.schedule
public.v_repairs -- view that joins fields from all tables above
Run Code Online (Sandbox Code Playgroud)
这非常有效,但假设开发人员(例如 Sally)想要测试一项新功能,用她自己的数据集来检查视觉反馈或阈值测试。她在自己的架构中创建了一个表sally.schedule。因为默认的search_path类似于"$user",public,所以她创建的任何简单查询都会在公开之前首先检查她的架构。例如:
SELECT * FROM schedule LEFT JOIN mechanics USING(mechanic_id);
Run Code Online (Sandbox Code Playgroud)
当 sally 连接到数据库时,这将使用 public.mechanics 和 sally.schedule。这正是预期的用途,但是在保存视图时,它通过插入架构来完全限定表名称。因此,如果将上面相同的查询创建为公共模式中的视图,它将如下所示:
SELECT * FROM public.schedule LEFT JOIN public.mechanics USING(mechanic_id);
Run Code Online (Sandbox Code Playgroud)
search_path 的魔力被否定了。当Sally连接到数据库调用视图时(SELECT * FROM v_mechanics_schedule ) 时,它会忽略她创建的 sally.schedule 表,而只使用公共表。
有没有办法在保存视图时不让 Postgres 存储表/视图对象的架构名称?
注意:这是我正在研究的新事物,但我从未真正需要过它,因为开发人员通常可以克隆应用程序、复制数据库并在自己的沙箱环境中工作。不需要一些巧妙的协作模式设置
在最后一天左右的时间里,我一直在为这个问题摸不着头脑——我只是不明白为什么一个过程在一种环境中有效,但由于转换错误(相同的数据,相同的代码)而在另一种环境中失败。
工作服务器的计划(大幅削减版本)位于: https: //www.brentozar.com/pastetheplan/ ?id=B1jZWTfOf
(这似乎不起作用,所以我已将计划 XML 上传到此处的 Pastebin: https: //pastebin.com/47Q6nniw)
导致问题的相关列的一些背景知识:
propertyInst 表包含一个名为 ValueStr 的列,它是 nvarchar 数据类型。GeneralLedgerCode 表具有数据类型 int 的列 id。我们的开发人员正在尝试连接两个表。ValueStr 列保存文本数据、XML 数据、整数数据、小数数据等。当然,我们决定添加一个函数来确保仅解析整数 (ISNUMERIC(ValueStr) = 1)。我们没有意识到的是,这也会尝试转换任何十进制值 - 这会导致自然生产中的转换错误:
将 nvarchar 值“0.1”转换为数据类型 int 时转换失败。
我的问题是,鉴于 propertyInst 表的表扫描将拾取包括小数在内的所有数值,为什么标量运算符中的隐式转换不会因相同的转换错误而失败?ISNUMERIC 查询的输出返回其中一些小数。我根本看不出所附计划是如何运作的。
隐式转换运算符是否永远不会彻底失败,转换错误是否来自哈希匹配运算符中的探测残差?话又说回来,当隐式转换失败时,该值如何能够到达运算符呢?
作为一个小帮助,计划图像在这里,我要询问的计算标量被圈起来。
此外,我可以看到没有针对标量运算符记录的实际行 - 这是否意味着引擎由于转换错误而决定在运行时不使用该特定运算符?
任何帮助,将不胜感激。
sql-server execution-plan type-conversion errors sql-server-2014
鉴于以下脚本,我可以看到隐式转换和数据类型优先级对查询计划有负面影响
-- create objects
CREATE DATABASE ConvertTest
GO
USE ConvertTest
GO
CREATE TABLE Person
(
VarcharId NVARCHAR(4),
IntId INT
)
-- insert data
INSERT INTO Person
SELECT TOP 1000
CONVERT(NVARCHAR(4),ROW_NUMBER() OVER (ORDER BY a.object_id)),
ROW_NUMBER() OVER (ORDER BY a.object_id)
FROM sys.objects a
CROSS JOIN sys.objects b
-- create indexes
CREATE INDEX IX_Varchar ON Person
(
VarcharId,
IntId
)
CREATE INDEX IX_Int ON Person
(
IntId,
VarcharId
)
DECLARE @id NVARCHAR(4) = 100
-- statement 1
SELECT * FROM …Run Code Online (Sandbox Code Playgroud) performance datatypes execution-plan type-conversion sql-server-2014
我在 StackOverflow 数据库中有以下 [相当无意义,仅用于演示] 查询:
SELECT *
FROM Users u
LEFT JOIN Comments c
ON u.Id = c.UserId OR
u.Id = c.PostId
WHERE u.DisplayName = 'alex'
Run Code Online (Sandbox Code Playgroud)
Users表上唯一的索引是 ID 上的聚集索引。
该Comments表具有以下非聚集索引以及 ID 上的聚集索引:
CREATE INDEX IX_UserID ON Comments
(
UserID,
PostID
)
CREATE INDEX IX_PostID ON Comments
(
PostID,
UserID
)
Run Code Online (Sandbox Code Playgroud)
查询的估计计划在这里:
我可以看到优化器将做的第一件事是对用户表执行 CI 扫描以仅过滤那些用户 where DisplayName = Alex,有效地执行此操作:
SELECT *
FROM Users u
WHERE u.DisplayName = 'alex'
ORDER BY Id
Run Code Online (Sandbox Code Playgroud)
并检索结果如下:
然后它会扫描评论 CI 并针对每一行,查看该行是否满足谓词 …
sql-server optimization execution-plan sql-server-2019 query-performance
为什么在通过链接服务器更新时使用 ISNULL() 使用远程扫描来检索所有行并在本地进行过滤,而不是通过远程查询进行过滤?
UPDATE LINKEDSERVER1.database1.dbo.table1 WITH(ROWLOCK)
SET number = ISNULL(number,0)
WHERE accounts = '123'
UPDATE LINKEDSERVER1.database1.dbo.table1 WITH(ROWLOCK)
SET number = number
WHERE accounts = '123'
Run Code Online (Sandbox Code Playgroud)
该表确实有一个针对帐户列的非聚集唯一索引,但 ISNULL() 未用于帐户列并且该索引应该仍然可用。我在这里错过了什么吗?
我有一个表,utc timestamptz其中的列上有一个“btree”索引utc:
CREATE TABLE foo(utc timestamptz)
CREATE INDEX ix_foo_utc ON foo (utc);
Run Code Online (Sandbox Code Playgroud)
该表包含大约5亿行数据。
当我utc使用 进行过滤时BETWEEN,查询规划器按预期使用索引:
> EXPLAIN ANALYZE
SELECT
utc
FROM foo
WHERE
utc BETWEEN '2020-12-01' AND '2031-02-15'
;
QUERY PLAN
Bitmap Heap Scan on foo (cost=3048368.34..11836322.22 rows=143671392 width=8) (actual time=12447.905..165576.664 rows=150225530 loops=1)
Recheck Cond: ((utc >= '2020-12-01 00:00:00+00'::timestamp with time zone) AND (utc <= '2031-02-15 00:00:00+00'::timestamp with time zone))
Rows Removed by Index Recheck: 543231
Heap Blocks: exact=43537 lossy=1818365
-> Bitmap …Run Code Online (Sandbox Code Playgroud) 我有一张表,其中包含 10 年的“包扫描”。有人扫描包裹并记录日期和用户名。现在让我们假设保留 10 年的数据实际上是有目的的。
我有一个页面显示过去一周的摘要,所以显然我只想阅读 1 周的数据。
以下是要在 SSMS 中运行两次的查询,一次使用硬编码的最近日期,另一次使用2013 年的旧日期。它最初是一个参数化查询,但在 SSMS 中我用@p0日期替换:
SELECT [t0].[VerifyDate], [t0].[PackageId], [t0].[Username]
FROM [dbo].[PackageVerification] AS [t0]
INNER JOIN [dbo].[Package] AS [t1] ON [t1].[PackageId] = [t0].[PackageId]
WHERE ([t1].[PackageStatus] <> 99) AND ([t0].[VerifyDate] > @p0)
ORDER BY [t0].[VerifyDate] DESC
Run Code Online (Sandbox Code Playgroud)
在执行之前,我想介绍一下我的日期索引。
现在,我的日期索引不在我的PackageVerification表上,而是在“辅助视图”上,该视图执行与上面所示的相同的连接。上面的查询能够神奇地使用这个索引视图,因为我启用了 SCHEMABINDING。
CREATE NONCLUSTERED INDEX [IX_Helper_PackageVerification_USER_SCAN_HISTORY] ON [dbo].[Helper_PackageVerification]
(
[VerifyDate] DESC,
[PackageStatus] ASC
)
INCLUDE (
[VerifyDateDate],
[Username]
)
Run Code Online (Sandbox Code Playgroud)
当我在 SSMS 中使用旧日期和新日期运行查询时,它会按预期使用扫描或查找。阈值似乎在 2015 年左右。所以任何最近的事情肯定都应该使用搜索。这是结果:
当我从应用程序中将其作为参数化查询运行时,我总是会得到完整扫描 …
sql-server execution-plan azure-sql-database parameter-sniffing
我们正在使用包含约 50M 记录的聚集列存储索引表,与使用相同的数据库架构和数据(刚刚导出和导入 bak 文件)在本地运行相比,在GCP云 sql 上运行时会遇到很大的性能下降。
使用下面的查询,我们发现GCP云sql( https://www.brentozar.com/pastetheplan/?id=ByexjqpCF )上的执行计划没有在索引扫描上使用projectId谓词,而是仅将其应用于进一步的过滤步骤。在本地运行时(https://www.brentozar.com/pastetheplan/?id=rJLO59pRK),谓词被推入索引扫描,从而减少扫描行数并提高性能。
造成这种差异的原因是什么?
SELECT YEAR(ReferenceDate) RefDateYear, MONTH(ReferenceDate) RefDateMonth,sum(diffsum) DiffSum
into #res
FROM Journal jp
WHERE jp.projectId='582b02e2-add0-4b50-94f7-4e7e07497cf6' AND ReferenceDate < '20220101' AND batch != 9998
GROUP BY YEAR(ReferenceDate), MONTH(ReferenceDate)
Run Code Online (Sandbox Code Playgroud)
另请参阅表架构:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Journal](
[id] [int] IDENTITY(1,1) NOT NULL,
[projectId] [uniqueidentifier] NOT NULL,
[diffSum] [money] NOT NULL,
[batch] [int] NOT NULL,
[referenceDate] [datetime2](7) NOT NULL,
...
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Journal] …Run Code Online (Sandbox Code Playgroud) 我在使用和不使用 OPTION (RECOMPILE) 的情况下执行了相同的查询。当我比较这两个计划时,我看到的一个主要区别是,没有选项重新编译的计划显示了很多 ComputeScalar 运算符,而另一个则没有。
以下是两个计划:
不带选项重新编译:https://www.brentozar.com/pastetheplan/ ?id=S1OcZGi85 带选项重新编译:https://www.brentozar.com/pastetheplan/ ?id=ryJAfMsL5
为什么一个计划使用大量计算标量,而另一个计划则不使用?不带选项重新编译的查询需要近 4 分钟才能执行。计算标量操作是否导致速度缓慢?
execution-plan ×10
sql-server ×7
postgresql ×2
columnstore ×1
datatypes ×1
errors ×1
index ×1
optimization ×1
performance ×1
recompile ×1
view ×1