- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
设想
我们有一个非常标准的数据导入过程,我们在其中加载staging
表,然后 MERGE
它变成了 target
table 。
新要求(绿色)涉及捕获导入数据的子集
成一个单独的 queue
表进行完全不相关的处理。
“挑战”
(1) 子集由一组记录组成:那些
新插入target
仅表。
(2) 子集是一些插入列的投影,但也
至少一列仅存在于源中(staging
table )。
(3) MERGE
语句已经使用了 OUTPUT..INTO
条款
严格记录$action
s 由 MERGE
拍摄,这样我们就可以PIVOT
结果和COUNT
插入次数、更新次数和
用于统计目的的删除。我们真的不喜欢缓冲
像这样对整个数据集进行操作,并且更喜欢聚合
即时的总和。不用说,我们不想添加更多数据到
此 OUTPUT
table 。
(4) 我们不想做 MERGE
的匹配工作
无论出于何种原因,即使是部分原因,第二次执行。这target
表真的很大,我们不能索引所有的东西,而且
操作通常非常昂贵(几分钟,而不是几秒钟)。
(5) 我们不考虑对 MERGE
的任何输出进行往返。到
客户端只是为了让客户端可以将其路由到 queue
经过
立即寄回。数据必须留在服务器上。
(6) 我们希望避免在临时存储中缓冲整个数据集
之间staging
和 queue
.
最好的方法是什么?
失败
(a) 仅将插入的记录入队的要求阻止了我们
从定位到 queue
表直接在 OUTPUT..INTO
的条款MERGE
,因为它不允许任何 WHERE
条款。我们可以使用一些CASE
标记不需要的记录以供后续删除的技巧
来自 queue
没有处理,但这似乎很疯狂。
(b) 因为有些列是为 queue
准备的不要出现在target
表,我们不能简单地在目标上添加插入触发器
表加载 queue
. “数据流拆分”必须更快发生。
(c) 因为我们已经使用了 OUTPUT..INTO
MERGE
中的条款, 我们
无法添加第二个 OUTPUT
子句和嵌套 MERGE
成INSERT..SELECT
加载队列。这是一种耻辱,因为它
感觉像是对有用的东西的完全任意限制
否则很好; SELECT
仅过滤具有$action
我们想要 ( INSERT
) 和 INSERT
他们在 queue
在一个
陈述。因此,DBMS 理论上可以避免缓冲整个
数据集并简单地将其流式传输到 queue
. (注:我们没有追求
并且很可能它实际上并没有以这种方式优化计划。)
情况
我们觉得我们已经用尽了我们的选择,但决定转向 hive 思维
为了确定。我们能想到的只有:
(S1) 创建 VIEW
的target
还包含可为空的表
用于 queue
的数据的列只有,并拥有SELECT
语句将它们定义为 NULL
.然后,设置 INSTEAD OF
填充 target
的触发器表和queue
适本地。最后,连接 MERGE
以定位 View 。这个
有效,但我们不是这个结构的粉丝——它绝对是
看起来很棘手。
(S2) 放弃,使用临时表缓冲整个数据集
另一个 MERGE..OUTPUT
.后 MERGE
, 立即复制数据
(再次!)从临时表到 queue
.
最佳答案
我的理解是,主要障碍是 OUTPUT
的限制。 SQL Server 中的子句。它允许一个 OUTPUT INTO table
和/或一个 OUTPUT
将结果集返回给调用者。
你想保存MERGE
的结果以两种不同的方式声明:
MERGE
影响的所有行用于收集统计信息 queue
MERGE
到
Target
本身只会执行一次)。下面有第二个变体,比较它们在真实数据上的表现会很有趣。
OUTPUT INTO @TempTable
在 MERGE
INSERT
来自 @TempTable
的所有行进入 Stats
或在插入前聚合。如果您只需要汇总统计数据,则可以汇总该批次的结果并将其合并到最终的 Stats
中。而不是复制所有行。 INSERT
进入 Queue
只有来自 @TempTable
的“插入”行. -- I'll return to commented lines later
CREATE TABLE [dbo].[TestTarget](
-- [ID] [int] IDENTITY(1,1) NOT NULL,
[foo] [varchar](10) NULL,
[bar] [varchar](10) NULL
);
CREATE TABLE [dbo].[TestStaging](
[foo] [varchar](10) NULL,
[bar] [varchar](10) NULL,
[baz] [varchar](10) NULL
);
CREATE TABLE [dbo].[TestStats](
[MergeAction] [nvarchar](10) NOT NULL
);
CREATE TABLE [dbo].[TestQueue](
-- [TargetID] [int] NOT NULL,
[foo] [varchar](10) NULL,
[baz] [varchar](10) NULL
);
TRUNCATE TABLE [dbo].[TestTarget];
TRUNCATE TABLE [dbo].[TestStaging];
TRUNCATE TABLE [dbo].[TestStats];
TRUNCATE TABLE [dbo].[TestQueue];
INSERT INTO [dbo].[TestStaging]
([foo]
,[bar]
,[baz])
VALUES
('A', 'AA', 'AAA'),
('B', 'BB', 'BBB'),
('C', 'CC', 'CCC');
INSERT INTO [dbo].[TestTarget]
([foo]
,[bar])
VALUES
('A', 'A_'),
('B', 'B?');
DECLARE @TempTable TABLE (
MergeAction nvarchar(10) NOT NULL,
foo varchar(10) NULL,
baz varchar(10) NULL);
MERGE INTO TestTarget AS Dst
USING TestStaging AS Src
ON Dst.foo = Src.foo
WHEN MATCHED THEN
UPDATE SET
Dst.bar = Src.bar
WHEN NOT MATCHED BY TARGET THEN
INSERT (foo, bar)
VALUES (Src.foo, Src.bar)
OUTPUT $action AS MergeAction, inserted.foo, Src.baz
INTO @TempTable(MergeAction, foo, baz)
;
INSERT INTO [dbo].[TestStats] (MergeAction)
SELECT T.MergeAction
FROM @TempTable AS T;
INSERT INTO [dbo].[TestQueue]
([foo]
,[baz])
SELECT
T.foo
,T.baz
FROM @TempTable AS T
WHERE T.MergeAction = 'INSERT'
;
SELECT * FROM [dbo].[TestTarget];
SELECT * FROM [dbo].[TestStats];
SELECT * FROM [dbo].[TestQueue];
TestTarget
+-----+-----+
| foo | bar |
+-----+-----+
| A | AA |
| B | BB |
| C | CC |
+-----+-----+
TestStats
+-------------+
| MergeAction |
+-------------+
| INSERT |
| UPDATE |
| UPDATE |
+-------------+
TestQueue
+-----+-----+
| foo | baz |
+-----+-----+
| C | CCC |
+-----+-----+
OUTPUT
子句可以将其结果集发送到表和调用者。所以,
OUTPUT INTO
可以进
Stats
如果我们直接包装
MERGE
语句转换成存储过程,然后我们可以使用
INSERT ... EXEC
进
Queue
.
INSERT ... EXEC
无论如何都会在幕后创建一个临时表(另见
The Hidden Costs of INSERT EXEC by
Queue
表应该只有“插入”行,而不是所有受影响的行。要实现这一点,您可以在
Queue
上使用触发器。表以丢弃“插入”以外的行。另一种可能性是使用
IGNORE_DUP_KEY = ON
定义唯一索引。并以这样一种方式准备数据,即“非插入”行将违反唯一索引并且不会插入到表中。
ID IDENTITY
列到
Target
表,我会添加一个
TargetID
列到
Queue
table 。 (在上面的脚本中取消注释它们)。
Queue
添加一个索引。 table :
CREATE UNIQUE NONCLUSTERED INDEX [IX_TargetID] ON [dbo].[TestQueue]
(
[TargetID] ASC
) WITH (
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = ON,
DROP_EXISTING = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
UNIQUE
和
IGNORE_DUP_KEY = ON
.
MERGE
的存储过程:
CREATE PROCEDURE [dbo].[TestMerge]
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
MERGE INTO dbo.TestTarget AS Dst
USING dbo.TestStaging AS Src
ON Dst.foo = Src.foo
WHEN MATCHED THEN
UPDATE SET
Dst.bar = Src.bar
WHEN NOT MATCHED BY TARGET THEN
INSERT (foo, bar)
VALUES (Src.foo, Src.bar)
OUTPUT $action INTO dbo.TestStats(MergeAction)
OUTPUT CASE WHEN $action = 'INSERT' THEN inserted.ID ELSE 0 END AS TargetID,
inserted.foo,
Src.baz
;
END
TRUNCATE TABLE [dbo].[TestTarget];
TRUNCATE TABLE [dbo].[TestStaging];
TRUNCATE TABLE [dbo].[TestStats];
TRUNCATE TABLE [dbo].[TestQueue];
-- Make sure that `Queue` has one special row with TargetID=0 in advance.
INSERT INTO [dbo].[TestQueue]
([TargetID]
,[foo]
,[baz])
VALUES
(0
,NULL
,NULL);
INSERT INTO [dbo].[TestStaging]
([foo]
,[bar]
,[baz])
VALUES
('A', 'AA', 'AAA'),
('B', 'BB', 'BBB'),
('C', 'CC', 'CCC');
INSERT INTO [dbo].[TestTarget]
([foo]
,[bar])
VALUES
('A', 'A_'),
('B', 'B?');
INSERT INTO [dbo].[TestQueue]
EXEC [dbo].[TestMerge];
SELECT * FROM [dbo].[TestTarget];
SELECT * FROM [dbo].[TestStats];
SELECT * FROM [dbo].[TestQueue];
TestTarget
+----+-----+-----+
| ID | foo | bar |
+----+-----+-----+
| 1 | A | AA |
| 2 | B | BB |
| 3 | C | CC |
+----+-----+-----+
TestStats
+-------------+
| MergeAction |
+-------------+
| INSERT |
| UPDATE |
| UPDATE |
+-------------+
TestQueue
+----------+------+------+
| TargetID | foo | baz |
+----------+------+------+
| 0 | NULL | NULL |
| 3 | C | CCC |
+----------+------+------+
INSERT ... EXEC
期间会有额外提示:
Duplicate key was ignored.
MERGE
更新了一些行。当唯一索引在
INSERT
期间丢弃某些行时发送此警告消息。由于
IGNORE_DUP_KEY = ON
.
A warning message will occur when duplicate key values are inserted into a unique index. Only the rows violating the uniqueness constraint will fail.
关于sql - DBMS 级别的管道和过滤器 : Splitting the MERGE output stream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34533204/
我正在使用 Assets 管道来管理我的 Grails 3.0 应用程序的前端资源。但是,似乎没有创建 CoffeeScript 文件的源映射。有什么办法可以启用它吗? 我的 build.gradle
我有一个我想要的管道: 提供一些资源, 运行一些测试, 拆资源。 我希望第 3 步中的拆卸任务运行 不管 测试是否通过或失败,在第 2 步。据我所知 runAfter如果前一个任务成功,则只运行一个任
如果我运行以下命令: Measure-Command -Expression {gci -Path C:\ -Recurse -ea SilentlyContinue | where Extensio
我知道管道是一个特殊字符,我需要使用: Scanner input = new Scanner(System.in); String line = input.next
我再次遇到同样的问题,我有我的默认处理方式,但它一直困扰着我。 有没有更好的办法? 所以基本上我有一个运行的管道,在管道内做一些事情,并想从管道内返回一个键/值对。 我希望整个管道返回一个类型为 ps
我有三个环境:dev、hml 和 qa。 在我的管道中,根据分支,阶段有一个条件来检查它是否会运行: - stage: Project_Deploy_DEV condition: eq(varia
我有 Jenkins Jenkins ver. 2.82 正在运行并想在创建新作业时使用 Pipeline 功能。但我没有看到这个列为选项。我只能在自由式项目、maven 项目、外部项目和多配置之间进
在对上一个问题 (haskell-data-hashset-from-unordered-container-performance-for-large-sets) 进行一些观察时,我偶然发现了一个奇
我正在寻找有关如何使用管道将标准输出作为其他命令的参数传递的见解。 例如,考虑这种情况: ls | grep Hello grep 的结构遵循以下模式:grep SearchTerm PathOfFi
有没有办法不因声明性管道步骤而失败,而是显示警告?目前我正在通过添加 || exit 0 来规避它到 sh 命令行的末尾,所以它总是可以正常退出。 当前示例: sh 'vendor/bin/phpcs
我们正在从旧的 Jenkins 设置迁移到所有计划都是声明性 jenkinsfile 管道的新服务器……但是,通过使用管道,我们无法再手动清除工作区。我如何设置 Jenkins 以允许 手动点播清理工
我在 Python 中阅读了有关 Pipelines 和 GridSearchCV 的以下示例: http://www.davidsbatista.net/blog/2017/04/01/docume
我有一个这样的管道脚本: node('linux'){ stage('Setup'){ echo "Build Stage" } stage('Build'){ echo
我正在使用 bitbucket 管道进行培训 这是我的 bitbucket-pipelines.yml: image: php:7.2.9 pipelines: default:
我正在编写一个程序,其中输入文件被拆分为多个文件(Shamir 的 secret 共享方案)。 这是我想象的管道: 来源:使用 Conduit.Binary.sourceFile 从输入中读取 导管:
我创建了一个管道,它有一个应该只在开发分支上执行的阶段。该阶段还需要用户输入。即使我在不同的分支上,为什么它会卡在这些步骤的用户输入上?当我提供输入时,它们会被正确跳过。 stage('Deplo
我正在尝试学习管道功能(%>%)。 当试图从这行代码转换到另一行时,它不起作用。 ---- R代码--原版----- set.seed(1014) replicate(6,sample(1:8))
在 Jenkins Pipeline 中,如何将工件从以前的构建复制到当前构建? 即使之前的构建失败,我也想这样做。 最佳答案 Stuart Rowe 还在 Pipeline Authoring Si
我正在尝试使用 执行已定义的作业构建 使用 Jenkins 管道的方法。 这是一个简单的例子: build('jenkins-test-project-build', param1 : 'some-
当我使用 where 过滤器通过管道命令排除对象时,它没有给我正确的输出。 PS C:\Users\Administrator> $proall = Get-ADComputer -filter *
我是一名优秀的程序员,十分优秀!