Oracle,限制每个用户的行数
Oracle, limit the row number per user
我需要限制查询可为特定用户 return 的行数。我知道我可以限制 SQL 查询,但我需要避免特定用户可以构建 return 大量行的查询。因此我需要限制配置。
有人知道这是否可行吗?
数据量不一定等于负载量。如果它足够复杂,单行查询可以杀死数据库。
这个问题的答案真的很复杂。
您可以获取 SQL 并从中创建一个 SQL 计划,并根据估计成本 and/or 估计行的数据限制。
How To Create and Evolve a SQL Plan Baseline
How do I display and read the execution plans for a SQL statement
示例:
我将创建一个临时 table:
create table tmp_table2 as
select * from user_objects;
然后我使用 Oracle 的计划估计而实际上 运行 查询
declare
l_sql varchar2 (32767);
begin
delete from plan_table;
l_sql := 'select * from tmp_table2';
execute immediate 'explain plan for ' || l_sql;
for i in (select cardinality,
cost,
bytes,
cpu_cost
from PLAN_TABLE
where operation = 'SELECT STATEMENT') loop
if i.cardinality /* rows */
> 500 then
dbms_output.put_line ('Too many rows');
elsif i.cpu_cost > 500000 then
dbms_output.put_line ('Too much CPU');
else
dbms_output.put_line ('About right');
end if;
end loop;
end;
结果;
==>
PL/SQL block executed
Too many rows
或者您可以使用资源管理器来限制每个会话:
您可以使用游标来实现。参见示例:
SQL> create or replace function exec_query(sql_text varchar2) return sys_refcursor
2 is
3 num_rows number := 3;
4 c1 sys_refcursor;
5 begin
6 open c1 for 'with test as (' || sql_text || ') select * from test where rownum <=' || num_rows ;
7 return c1;
8 end;
9 /
Function created.
SQL> variable c1 refcursor;
SQL> exec :c1 := exec_query('select last_name, salary from hr.employees');
PL/SQL procedure successfully completed.
SQL> print :c1;
LAST_NAME SALARY
------------------------- ----------
King 24000
Kochhar 17000
De Haan 17000
如果您有企业版,您可以使用 DBMS_RLS 包实施 VPD 规则:
SQL> create or replace package pac1
2 is
3 function limit_rows(owner varchar2, tab varchar2) return varchar2;
4 end;
5 /
Package created.
SQL> create or replace package body pac1
2 is
3 function limit_rows(owner varchar2, tab varchar2) return varchar2
4 is
5 begin
6 return ' rownum <= 3';
7 end;
8 end pac1;
9 /
Package body created.
SQL> begin
2 dbms_rls.add_policy('HR','EMPLOYEES','RULE1','HR','PAC1.LIMIT_ROWS','SELECT');
3 end;
4 /
PL/SQL procedure successfully completed.
SQL> select first_name, last_name from hr.employees;
FIRST_NAME LAST_NAME
-------------------- -------------------------
Ellen Abel
Sundar Ande
Mozhe Atkinson
SQL>
我需要限制查询可为特定用户 return 的行数。我知道我可以限制 SQL 查询,但我需要避免特定用户可以构建 return 大量行的查询。因此我需要限制配置。
有人知道这是否可行吗?
数据量不一定等于负载量。如果它足够复杂,单行查询可以杀死数据库。
这个问题的答案真的很复杂。
您可以获取 SQL 并从中创建一个 SQL 计划,并根据估计成本 and/or 估计行的数据限制。
How To Create and Evolve a SQL Plan Baseline
How do I display and read the execution plans for a SQL statement
示例: 我将创建一个临时 table:
create table tmp_table2 as
select * from user_objects;
然后我使用 Oracle 的计划估计而实际上 运行 查询
declare
l_sql varchar2 (32767);
begin
delete from plan_table;
l_sql := 'select * from tmp_table2';
execute immediate 'explain plan for ' || l_sql;
for i in (select cardinality,
cost,
bytes,
cpu_cost
from PLAN_TABLE
where operation = 'SELECT STATEMENT') loop
if i.cardinality /* rows */
> 500 then
dbms_output.put_line ('Too many rows');
elsif i.cpu_cost > 500000 then
dbms_output.put_line ('Too much CPU');
else
dbms_output.put_line ('About right');
end if;
end loop;
end;
结果;
==>
PL/SQL block executed
Too many rows
或者您可以使用资源管理器来限制每个会话:
您可以使用游标来实现。参见示例:
SQL> create or replace function exec_query(sql_text varchar2) return sys_refcursor
2 is
3 num_rows number := 3;
4 c1 sys_refcursor;
5 begin
6 open c1 for 'with test as (' || sql_text || ') select * from test where rownum <=' || num_rows ;
7 return c1;
8 end;
9 /
Function created.
SQL> variable c1 refcursor;
SQL> exec :c1 := exec_query('select last_name, salary from hr.employees');
PL/SQL procedure successfully completed.
SQL> print :c1;
LAST_NAME SALARY
------------------------- ----------
King 24000
Kochhar 17000
De Haan 17000
如果您有企业版,您可以使用 DBMS_RLS 包实施 VPD 规则:
SQL> create or replace package pac1
2 is
3 function limit_rows(owner varchar2, tab varchar2) return varchar2;
4 end;
5 /
Package created.
SQL> create or replace package body pac1
2 is
3 function limit_rows(owner varchar2, tab varchar2) return varchar2
4 is
5 begin
6 return ' rownum <= 3';
7 end;
8 end pac1;
9 /
Package body created.
SQL> begin
2 dbms_rls.add_policy('HR','EMPLOYEES','RULE1','HR','PAC1.LIMIT_ROWS','SELECT');
3 end;
4 /
PL/SQL procedure successfully completed.
SQL> select first_name, last_name from hr.employees;
FIRST_NAME LAST_NAME
-------------------- -------------------------
Ellen Abel
Sundar Ande
Mozhe Atkinson
SQL>