增强大型慢速数据加载查询的性能

时间:2009-09-25 13:25:58

标签: c# .net sql oracle plsql

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

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

例如:

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;

6 个答案:

答案 0 :(得分:4)

  

我正在获得每一行并表演   C#中的逻辑然后插入

如果可能,请从SELECT中输入:

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

这将比单个查询更快地运行 ,然后循环结果集并为每一行设置INSERT。

对OP问题编辑

编辑

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

编辑基于OP最近的评论:

因为您正在将数据从Oracle加载到SQL Server中,所以我会这样做:大多数人可以提供帮助而不会再次阅读此问题,因此请打开一个新问题:1)您需要要将数据从Oracle(版本)加载到SQL Server版本2),目前您正在从处理C#中每一行的一个查询加载它并将其插入SQL Server,这很慢。以及所有其他细节。有更好的方法可以将数据批量加载到SQL Server中。至于这个问题,你可以接受一个答案,回答你自己在哪里解释你需要提出一个新问题,或者只是让它不被接受。

答案 1 :(得分: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

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

更好的方法是在SELECT中更新支持函数以包含连接标准(IE:“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

我更喜欢为了维护而必须将函数逻辑合并到查询中,但有时它无法帮助。

答案 2 :(得分:1)

就个人而言,我会创建一个SSIS导入来执行此任务。使用abulk插入可以大大提高速度,SSIS可以在批量插入后处理功能部分。

答案 3 :(得分:0)

在桌面上创建一个已排序的整数。

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

编辑问题以来编辑:

使用视图甚至更不理想,尤其是从查询单行时。我认为你的“业务功能”实际上就像存储过程一样?

正如其他人所说,在SQL中总是以set为基础。我以为你已经这样做了,因此我的提示开始使用索引。

答案 4 :(得分:0)

一些提示:

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

答案 5 :(得分:0)

首先,您需要找到性能问题的实际位置。然后你可以试着解决它。

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

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

    create table the_view_table
    as
    select *
    from the_view;
    
  2. 这些功能的表现如何?根据描述,您正在进行大约500万次函数调用。他们最好效率很高!定义为deterministic的函数也是如此。如果使用deterministic关键字定义函数,则Oracle有可能优化一些调用。

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

    select 
      f.dim_id, 
      d.dim_col_1, 
      long_slow_function(d.dim_col_2) as dim_col_2
    from large_fact_table f
    join small_dim_table d on (f.dim_id = d.dim_id)
    select 
      f.dim_id, 
      d.dim_col_1, 
      d.dim_col_2
    from large_fact_table f
    join (
      select 
        dim_id, 
        dim_col_1, 
        long_slow_function(d.dim_col_2) as dim_col_2
    from small_dim_table) d on (f.dim_id = d.dim_id)

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

  4. 性能问题可能出在上述任何一个地方,在您调查问题之前,很难知道在哪里指导您的调优工作。