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

MSSQL
如何让新安装的MySQL数据库变得更安全
考虑SQL Server安全时所应注意的几个方面
快速解决SQL server 2005孤立用户问题
比较一下看看自己掌握了多少SQL快捷键
怎样在SQL Server 2005中用证书加密数据
讲解使用SQL Server升级顾问的详细步骤
讲解设计应用程序时避免阻塞的八个准则
配置SQL Server文件组对应不同的RAID系统
讲解数据库管理系统必须提供的基本服务
讲解SQL Server2005数据项的分拆与合并
SQL Server数据库动态交叉表的参考示例
SQL SERVER 2005中的同步复制技术
SQL Server查询速度慢的原因及优化方法
减少SQL Server死锁的方法
sql server 视图作用
扩展数据库系统选项实现更高的可扩展性
SQL Server开发过程中的的常见问题总结
对跨多个表格的数据组合时需要用到的SQL
SQL Server 2005 FOR XML嵌套查询使用详解
另类解读SQL Server中的DateTime数据类型

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


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-10-17   浏览: 119 ::
收藏到网摘: 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>');