【问题标题】:Lengthy SQL stored procedure with tables storing more and more columns冗长的 SQL 存储过程,表存储越来越多的列
【发布时间】:2011-10-22 16:01:41
【问题描述】:

此问题适用于用 SQL-92 编写的存储过程
即 Oracle PL/SQL、SQL Server T-SQL 或 DB2 SQL

我正在维护一个 11000 行的存储过程。
我发现在存储过程结束时我需要报告 80 列数据。

这个存储过程有 3 个不同的阶段。

  1. 数据收集(将数据从活动表复制到存储过程中间表)
    我需要进行数据收集以保持一致性,因为在存储过程执行到第 10,000 行时,第 30 行的实时数据(即在成员表中)可能已经发生了变化
    提交状态原子性在此处保持(在复制所需的所有数据之前不提交)
  2. 计算(大量 SQL,足够复杂以至于游标或视图无法完成工作)
  3. 写回永久表(发票、AR、付款)
    提交状态原子性在此处保持(在复制所需的所有数据之前不提交)

“中间”表仅用于存储过程。
它们被索引用于连接下线但没有
PK/FK 参照完整性约束或唯一索引
因为这些会大大减慢执行速度
指向实时数据(不断变化)

当您在存储结束时需要报告 80 列数据时
您遇到 RDBMS 限制(索引限制、内存限制、
SQL 连接 COST 限制、失控分页和数据进入虚拟
当数据库认为它应该使用 HASH 而不是使用 NESTED LOOPS 时进行内存/交换)

我已经标准化 LIVE 数据(数据输入用户 24/7 全天候写入和读取)

突然想到优化中间表占用空间的方法
在存储过程中使用(在第 2 步)将查找复合主键并分配
每个都有一个唯一的 id(代理 PK),从而用 1 列引用 n 列。然后,我
将在第 2 步结束时重构此数据并准备好
在第 3 步开始时写回。这将增加更多处理
第 2 步,但会复制更少的数据。也需要调试
更多步骤(将 id 追溯到中间的实际数据
执行完成后的表数据)

有没有人遇到过使用冗长存储过程的场景?
是否有人在
中创建了代理键(用单列 PK 替换复合 PK) 仅在存储过程中使用的中间表?

这在执行时间和期间使用的内存/空间方面是否得到了回报
执行?

【问题讨论】:

  • 你说的是十一千行存储过程吗??
  • 每次执行存储过程时:您要为其创建临时表的数据量是多少?直观地说,一个 11 000 行的存储过程听起来像是一种错误的方法。您能否编写一个 C# 应用程序,在计算过程中处理内存中所需的数据?
  • @Simen S 它实际上是数据库大小的两倍。当存储过程已经在 SQL 中进行非常复杂的数据处理(处理数据块)时,C# 逐行处理就不是一个选项
  • 创建代理键(用单列 PK 替换复合 PK)不是规范化。这甚至不是正常化(如果你是英国人):)
  • @n8wrl 是的,你没看错。这些要求需要根据大量评级因素(大量计数、分组、SQL 函数、时间计算)进行大量计算(它是为保险业 TPA 编写的)。输入不是微不足道的,结果也不是。并不是要开始一场语言大战,但在 SQL 中,我需要做的所有事情都需要 1/2 的时间来阅读和修改。它很简洁。一切都在块中处理。它是声明性的,它干净且容易。这在 C# 中是无法管理的。

标签: sql sql-server oracle stored-procedures normalization


【解决方案1】:

而且我认为我的 1400 行 proc 很长!

我可以看到代理键在连接中比复合 PK 更快的地方。但是对于如此复杂的任何事情,我认为您只需要尝试两种方式即可。

你能减少 80 列吗?我想我是在问您是否使用 select * 与连接,其中连接字段将在查询中重复并且可以省略。

【讨论】:

  • 没有明显的重复多字段连接。真正归结为我需要找到/构建一个工具,将 SQL 连接条件回溯到以前的选择项并建议代理主键。
  • 我只能说,这似乎是一个合理的尝试,但您必须仔细衡量,看看是否存在真正的性能差异。
【解决方案2】:

为什么不尝试编写 SSIS 包。除了写入临时表之外,您的大部分计算都将在 SSIS 内存中,而不会打扰数据库。

您可以根据需要分解包的任意数量,并且流程更易于维护。

顺便说一句,11K sproc 太疯狂了……忍不住,不得不说 :-)

【讨论】:

  • 我没有想到 SSIS。 SSIS 用于 ETL 操作等,将存储过程转换为 SSIS 包将是维护的噩梦。
  • 我知道 11K 声明式 SQL 很疯狂,但替代方案(22K、33K -- 在此处选择您的命令式语言)更疯狂。命令式语言逐行处理数据,无法在进程中间调试数据。如果最终结果有问题,我需要查看剩余的中间表数据。我已经使用嵌入式 DB2 SQL 调用等完成了 Pro*C、C#、C。他们没有削减它。
【解决方案3】:

我已经构建了一些长 SProcs,并且我一直都在使用 Indentity 列代理键。是否可以重新考虑正在做的事情并为每个中间步骤创建单独的临时表?

过去我不得不这样做。最后,我将所有单独的临时表“拼接”到我的最终输出中。

【讨论】:

  • 对,这正是我想做的。在 SQL Server 中是 Identity 列,在 Oracle 中是 SEQUENCE,在 DB2 中是 AS IDENTITY GENERATED BY DEFAULT in IBM DB2。
【解决方案4】:

“我需要进行数据收集以保持一致性,因为在存储过程执行到第 10,000 行时,第 30 行的 LIVE 数据(即在成员表中)可能已经更改”

在 Oracle 中,您可以查看 DBMS_FLASHBACK(或 SERIALIZABLE 隔离级别)以获得此级别的一致性。闪回查询可能会避免您需要复制所有数据。

我为数据迁移做了一个类似的练习——大量的临时表。要检查的一个因素是在适当的时间点为临时表收集统计信息。如果这些表通常是空的,那么统计数据可能会在最后搞砸。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-15
    • 2018-11-27
    • 1970-01-01
    • 2020-09-13
    • 2016-01-09
    • 1970-01-01
    相关资源
    最近更新 更多