当前位置: 首页 > 图文教程 > 数据库 > MSSQL > 避免在 PL/SQL 中使用嵌套游标查询

MSSQL
MS SQL SERVER2005 XML 最佳实践
SQL Server对文件进行全文检索的查询
教你构建SQL Server可管理安全机制
维护SQL Server的交易日志经验总结
SQL SERVER 2005 EXPRESS不能远程连接的问题
SQL Server与Oracle并行访问本质区别
SQL Server数据库优化其索引的小技巧
分析及解决SQLServer死锁问题
用SQL Server为Web浏览器提供图像
SQL Server SQL Agent服务使用小结
SQL Server 存储过程的分页方案比拼
SQL Server数据库中存储引擎深入探讨
四招解决SQL Server对上亿表的排序和join的问题
SQL Server数据库管理员必须掌握的DBCC命令
如何将sql数据库的文件备份到本地?
如何解决Sybase数据库乱码问题详解
SQL Server:SQLServer中最小函数依赖集
小编谈Transact-SQL中的一些命名规范
谈SQL编写规范
浅谈SQL命名与注释规范

MSSQL 中的 避免在 PL/SQL 中使用嵌套游标查询


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-17   浏览: 40 ::
收藏到网摘: n/a

考虑下面的 PL/SQL 代码,这段代码生成一个 XML 格式的矩阵样式的报表:

以下为引用的内容:

  declare
  l_count   integer;
  begin
  dbms_output.put_line('<matrix>');
  -- generate matrix of parts by country
  for part in (select id,description from parts order by description) loop
  dbms_output.put_line('<row>');
  dbms_output.put_line('<cell>'part.description'</cell>');
  for country in (select code from countries order by name) loop
  select sum(cnt) into l_count from orders
  where part_id = part.id and cc = country.code;
  dbms_output.put_line('<cell>'nvl(l_count,0)'</cell>');
  end loop;
  dbms_output.put_line('</row>');
  end loop;
  dbms_output.put_line('</matrix>');
  end;

假如在这个例子中 parts 和 countries 有很多行数据,那么性能就会趋于下降。这是因为,在 PL/SQL 中,每次碰到一个游标 FOR 循环,在重新查询并获得数据时,都会有一个切换到 SQL 的上下文切换。

以一些服务器端内存为代价,提高这种构造的速度是有可能做到的——假如动态构建 PL/SQL 数据表和矩阵单元格条目就可以提高速度。例如:

以下为引用的内容:

  declare
  type part_tbl_type is table of parts%rowtype index by binary_integer;
  part_tbl   part_tbl_type;
  --
  type country_tbl_type is table of countries%rowtype index by binary_integer;
  country_tbl   country_tbl_type;
  --
  type cell_rec is record
  (
  part_id     orders.part_id%type,
  cc        orders.cc%type,
  cnt        orders.cnt%type
  );
  type cell_tbl_type is table of cell_rec index by binary_integer;
  cell_tbl cell_tbl_type;
  --
  i pls_integer;
  begin
  -- build rows
  for row in (select * from parts order by description) loop
  part_tbl(part_tbl.count+1) := row;
  end loop;
  -- build columns
  for col in (select * from countries order by name) loop
  country_tbl(country_tbl.count+1) := col;
  end loop;
  -- build cells
  for cell in (select part_id,cc,sum(cnt) from orders group by part_id,cc) loop
  cell_tbl(cell_tbl.count+1) := cell;
  end loop;
  dbms_output.put_line('<matrix>');
  -- generate matrix of parts by country
  i := cell_tbl.first;
  for row in part_tbl.first .. part_tbl.last loop
  dbms_output.put_line('<row>');
  dbms_output.put_line('<cell>'part_tbl(row).description'</cell>');
  for col in country_tbl.first .. country_tbl.last loop
  if cell_tbl(i).part_id = part_tbl(row).id
  and cell_tbl(i).cc = country_tbl(col).code
  then
  dbms_output.put_line('<cell>'cell_tbl(i).cnt'</cell>');
  i := i + 1;
  else
  dbms_output.put_line('<cell>0</cell>');
  end if;
  end loop;
  dbms_output.put_line('</row>');
  end loop;
  dbms_output.put_line('</matrix>');
  end;

游标

游标的 FOR 循环现在是独立运行的,并且特定记录、特定字段、特定单元格的数据被拷贝到三个 PL/SQL 表中。

然后利用记录和字段具有特定顺序这一事实,将结果构建到一个 PL/SQL 表的矩阵中。由于 GROUP BY 的隐式 SORT/MERGE 操作,单元格具有同样的顺序。单元格查询已经被减少到一个查询,替代了原来的矩阵每个单元格使用一个查询。

假如字段的数目相当小,那么我们可以使用 BULK COLLECT 构建表。BULK COLLECT 不答应表记录的填充,所以我们就需要为用于这个操作的每一列数据创建一个独立的表。前面的例子可以采用 BULK COLLECT 重写为另外一种形式。

以下为引用的内容:

  declare
  type part_id_tbl_type is table of parts.id%type;
  type part_desc_tbl_type is table of parts.description%type;
  part_id_tbl     part_id_tbl_type;
  part_desc_tbl   part_desc_tbl_type;
  --
  type country_code_tbl_type is table of countries.code%type;
  country_code_tbl   country_code_tbl_type;
  --
  type cell_cnt_tbl_type is table of orders.cnt%type;
  cell_part_id_tbl   part_id_tbl_type;
  cell_country_tbl   country_code_tbl_type;
  cell_cnt_tbl     cell_cnt_tbl_type;
  --
  i pls_integer;
  begin
  -- gather rows
  select id,description
  bulk collect into part_id_tbl,part_desc_tbl
  from parts
  order by description;
  -- gather columns
  select code
  bulk collect into country_code_tbl
  from countries
  order by name;
  -- gather cells
  select part_id,cc,sum(cnt)
  bulk collect into cell_part_id_tbl,cell_country_tbl,cell_cnt_tbl
  from orders
  group by part_id,cc;
  dbms_output.put_line('<matrix>');
  -- generate matrix of parts by country
  i := cell_cnt_tbl.first;
  for row in part_id_tbl.first .. part_id_tbl.last loop
  dbms_output.put_line('<row>');
  dbms_output.put_line('<cell>'part_desc_tbl(row)'</cell>');
  for col in country_code_tbl.first .. country_code_tbl.last loop
  if cell_part_id_tbl(i) = part_id_tbl(row)
  and cell_country_tbl(i) = country_code_tbl(col)
  then
  dbms_output.put_line('<cell>'cell_cnt_tbl(i)'</cell>');
  i := i + 1;
  else
  dbms_output.put_line('<cell>0</cell>');
  end if;
  end loop;
  dbms_output.put_line('</row>');
  end loop;
  dbms_output.put_line('</matrix>');