【问题标题】:Enhance performance of large slow dataloading query提高大型慢速数据加载查询的性能
【发布时间】:2009-09-25 13:25:57
【问题描述】:

我正在尝试将数据从 oracle 加载到 sql server(抱歉之前没有写过这个)

我有一个至少有 100 万条记录的表(实际上是一个包含来自不同表的数据的视图)。我以这样一种方式设计了我的包,即我具有业务逻辑功能并直接在选择查询中调用它们。

例如:

X1(id varchar2)
x2(id varchar2, d1 date)
x3(id varchar2, d2 date)

Select id, x, y, z, decode (.....), x1(id), x2(id), x3(id) 
FROM Table1

注意:我的表有 20 列,我在至少 6-7 列上调用 5 个不同的函数。 并且一些函数将传递的参数与审计表进行比较并执行逻辑

如何提高查询的性能或有更好的方法来做到这一点

我尝试在 C# 代码中执行此操作,但初始选择的记录对于数据集来说足够大,并且出现内存不足异常。

我的函数会选择然后执行逻辑,例如:

Function(c_x2, eid) 

  Select col1 
    into p_x1 
    from tableP 
   where eid = eid; 

  IF (p_x1 = NULL) THEN 
    ret_var := 'INITIAL'; 
  ELSIF (p_x1 = 'L') AND (c_x2 = 'A') THEN 
    ret_var:= 'RL'; 

    INSERT INTO Audit
      (old_val, new_val, audit_event, id, pname) 
    VALUES 
      (p_x1, c_x2, 'RL', eid, 'PackageProcName'); 

  ELSIF (p_x1 = 'A') AND (c_x2 = 'L') THEN 
    ret_var := 'GL'; 

    INSERT INTO Audit
      (old_val, new_val, audit_event, id, pname) 
    VALUES 
      (p_x1, c_x2, 'GL', eid, 'PackgProcName'); 

  END IF; 

RETURN ret_var;

【问题讨论】:

  • 您要为所有 1,000,000 条记录运行这些函数吗?是的,它需要一些时间来运行——当然不是毫秒。您的期望是什么?
  • 我从来没有说过我想要毫秒,它运行了 1 小时..所以我想提高(增强)性能我说过......我没有写我希望它完成一眨眼

标签: c# .net sql oracle plsql


【解决方案1】:

我正在获取每一行并执行 C#中的逻辑然后插入

如果可能,从 SELECT 中插入:

INSERT INTO YourNewTable
        (col1, col2, col3)
    SELECT
        col1, col2, col3
        FROM YourOldTable
        WHERE ....

这将比单个查询运行显着快,然后循环遍历结果集并为每一行插入一个查询。

EDIT 至于 OP 问题编辑:

您应该能够在查询中将函数调用替换为纯 SQL。使用 LEFT JOIN tableP 模拟“初始”,并且可以使用 CASE 计算“RL”或“GL”。

EDIT 基于 OP 最近的 cmets:

由于您正在将数据从 Oracle 加载到 SQL Server,这就是我要做的:大多数可以提供帮助的人已经继续前进并且不会再阅读这个问题,所以请在您说的地方打开一个新问题:1)您需要将数据从 Oracle(版本)加载到 SQL Server 版本 2)当前您正在从一个查询中加载它,处理 C# 中的每一行并将其插入 SQL Server,它很慢。以及所有其他细节。有很多更好的方法可以将数据批量加载到 SQL Server 中。对于这个问题,您可以接受一个答案,在您解释需要提出新问题的地方回答自己,或者不接受它。

【讨论】:

  • insert into select 对我不起作用,因为我正在将 oracle 表加载到 sql server 如果我使用 CASE,我无法进行插入审计
  • 哇! i'm loading oracle table to sql server 不是你提出的问题吗?就在顶部附近??
【解决方案2】:

我的建议是您不要使用函数,然后在其他 SELECT 语句中调用它们。这个:

SELECT t.id, ...
       x1(t.id) ...
  FROM TABLE t

...等价于:

SELECT t.id, ...
       (SELECT x.column FROM x1 x WHERE x.id = t.id)
  FROM TABLE t

在使用 C#/etc 时,封装在 SQL 中不起作用。虽然该方法使维护更容易,但性能会受到影响,因为子选择将对返回的每一行执行。

更好的方法是更新支持函数以在 SELECT 中包含连接条件(即:“where x.id = t.id”,因为缺少真正的连接条件):

SELECT x.id
       x.column 
  FROM x1 x

...所以您可以将其用作 JOIN:

SELECT t.id, ...
       x1.column
  FROM TABLE t
  JOIN (SELECT x.id,
               x.column 
          FROM MY_PACKAGE.x) x1 ON x1.id = t.id

我更喜欢为了维护而将功能逻辑合并到查询中,但有时它无济于事。

【讨论】:

  • +1,这里工作有多个问题,我想到了这个,但只是从 SELECT 中插入。你对功能问题的解释比我还好......
  • 有人可以帮我编辑上面的评论吗..我想添加代码sn-p
  • 编辑您的问题并将代码放在那里,据我所知,您只能在 cmets 中 BOLDITALICS,没有代码格式
【解决方案3】:

我个人会创建一个 SSIS 导入来完成这项任务。使用 abulk insert 可以显着提高速度,并且 SSIS 可以处理 bulk insert 之后的功能部分。

【讨论】:

    【解决方案4】:

    首先,您需要找到性能问题的实际出处。然后你可以看看尝试解决它。​​

    1. 视图的性能如何?视图执行需要多长时间 没有任何函数调用?尝试运行命令

      它的表现如何?需要 1 分钟还是 1 小时?

      创建表 the_view_table 作为 选择 * 从the_view;
    2. 函数的性能如何?根据描述,您正在进行大约 500 万次函数调用。他们最好效率很高!还有定义为deterministic 的函数。如果函数是使用deterministic 关键字定义的,Oracle 就有机会优化掉一些调用。

    3. 有没有办法减少函数调用的次数?一旦评估了视图并且有数百万行数据可用,就会调用该函数。但是是查询最高级别的所有输入值吗?函数调用是否可以嵌入到较低级别的视图中。考虑以下两个查询。哪个更快?

      选择
        f.dim_id,
        d.dim_col_1,
        long_slow_function(d.dim_col_2) 作为 dim_col_2
      来自 large_fact_table f
      加入 small_dim_table d on (f.dim_id = d.dim_id)
      选择
        f.dim_id,
        d.dim_col_1,
        d.dim_col_2
      来自 large_fact_table f
      加入 (
        选择
          昏暗的ID,
          dim_col_1,
          long_slow_function(d.dim_col_2) 作为 dim_col_2
      从 small_dim_table) d on (f.dim_id = d.dim_id)

      理想情况下,第二个查询应该运行得更快,因为它调用函数的次数更少。

    性能问题可能出现在任何这些地方,在您调查问题之前,很难知道将调优工作指向何处。

    【讨论】:

    • 谢谢你,我将再次通过函数和查询,看看如何避免不必要的调用..
    【解决方案5】:

    几个提示:

    • 不要将所有记录都加载到 RAM 中,而是一个一个地处理它们。
    • 尝试在客户端上运行尽可能多的功能。数据库执行用户定义的函数真的很慢。
    • 如果您需要连接两个表,有时可以在客户端上创建两个连接。使用连接 1 获取数据主数据,使用连接 2 获取审计数据。以相同的方式对两个连接的数据进行排序,以便您可以从两个连接中读取单个记录并对它们执行任何您需要的操作。
    • 如果您的函数总是为相同的输入返回相同的结果,请使用计算列或物化视图。数据库将运行该函数一次并将其保存在某处的表中。这将使INSERT 变慢但SELECT 变快。

    【讨论】:

    • 我在 c# 中使用 datareader 编写了相同的代码,我在其中获取每一行并在 C# 中执行逻辑然后插入......这也需要很多时间......我使用的函数带参数并对此执行一些逻辑:比如比较然后计算日期或其他数据......我没有在我的查询中使用任何连接
    • (-1) 使用基于集合的 SQL - 不逐条记录。尝试使用速度很快的原生 SQL 函数。将数据库用作数据库 - 它是为连接/更新/查询而构建的。不要以为我们的编程技能就可以重写数据库。
    • 我在 C# 中而不是在 sql 中执行函数,如果我尝试在内存中一次加载所有内容,则会引发内存不足异常,这就是我使用 datareader 的原因......我知道db 是为...而构建的...我正在尝试获得答案并学习不要重写 db plz...
    【解决方案6】:

    在你的表上创建一个排序的 intex。

    Introduction to SQL Server Indizes,其他RDBMS类似。

    编辑,因为您编辑了您的问题:

    使用视图更加次优,尤其是在从中查询单行时。我认为您的“业务功能”实际上类似于存储过程?

    正如其他人所建议的,在 SQL 中总是基于集合。我假设您已经这样做了,因此我建议您开始使用索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-13
      • 1970-01-01
      • 2016-07-19
      • 1970-01-01
      • 2012-04-19
      相关资源
      最近更新 更多