借助内存表处理复杂的oracle查询要求
借助内存表处理复杂的 oracle 查询要求 . 在日常业务处理过程中 , 我们经常会碰到一些非常规的查询需求 , 这些需求我们或者可以借助动态语句 , 或者其他现有的 oracle 函数完成查询结果 , 但效率往往差强人意 . 假设我们有一个客户订单业务表 { 订单号 , 订
借助内存表处理复杂的oracle查询要求.
在日常业务处理过程中,我们经常会碰到一些非常规的查询需求, 这些需求我们或者可以借助动态语句,或者其他现有的oracle函数完成查询结果, 但效率往往差强人意.
假设我们有一个客户订单业务表{订单号, 订单客户, 订单日期, 数量, 金额}存储了订单的往来明细数据,订单表中保存最近3个月的往来明细共1000w条记录, 其中客户总量约500000. 并假定在订单表上有针对日期和客户的单独索引.
现在要求提供对任意集合的多个客户的某段时间的订单明细数据.
Select 订单号, 订单客户, 订单日期, 数量, 金额
From 订单业务表
Where 订单日期 between 开始日期 and 结束日期
And 订单客户 in (客户1, 客户2, 客户3…)
面对这种需求, 我们可以要求前台程序传回三个参数, 开始日期, 结束日期, 客户列表(类似于客户1, 客户2, 客户3, 客户4…)
一, 创建测试用表.
Create table t_order_cust(
O_id varchar2(20),
O_customer varchar2(20),
O_date date,
O_qty numeric(18,2),
O_amount numeric(18,2)
);
Create index ind_t_order_cust_01 on t_order_cust(o_customer);
Create index ind_t_order_cust_02 on t_order_cust(o_date);
二, 方法1 , 使用动态语句拼凑实现.
针对上述查询, 我们可以拼凑动态语句实现, 如下代码所示.
Declare
V_beg_date date := trunc(sysdate,’month’);
V_end_date date := trunk(sysdate);
V_cust_str varchar2(1000) := ‘’’客户1’’, ’’客户2’’, ’’客户3’’…’;
V_sql_str varchar2(2000) ;
Begin
V_sql_str := ‘select * from t_order_cust
Where o_date between ’ || v_beg_date || ‘ and ’ || v_end_date ||’
And o_customer in (’||v_cust_str||’)’;
Execute immediate v_sql_str;
End;
根据表明细数据的特点我们知道, 客户索引的选择性为 1000w/50w= 20, 而日期索引的选择性为 1000w/(3*30) = 10w, 明显使用日期索引效率极差, 我们只能选择使用客户上的索引,使用这种处理方法的优势是可以用到客户上的索引, 但in使用索引的效率相对较差, 并且这种处理方式下, oracle每次执行查询都需要重新建立查询执行树, 也是需要一定的额外开销.
三, 方法2 使用like查询
除了上面的拼凑动态执行语句的方法之外, 我们可以设想的到的第二种方法就是借助于oracle提供的like功能. 如下代码所示.这种处理方式下对客户列表字符串的要求跟方法一少有区别.
Declare
V_beg_date date := trunc(sysdate,’month’);
V_end_date date := trunk(sysdate);
V_cust_str varchar2(1000) := ‘客户1, 客户2, 客户3…’;
Begin
select * from t_order_cust
Where o_date between v_beg_date and v_end_date
And v_cust_str like ‘%’||o_customer||’%’;
End;
这种处理方式的优点在于代码书写简单, 但由于对客户索引所在字段o_customer做了拼接处理||, 所以将导致客户索引ind_t_order_cust_01无效, 而只能使用效率较差的日期索引. 在数据量较小, 对效率无法造成影响时这种方法可以接受, 但数据量较大时, 这种方法的缺点将是致命的.
四, 方法3 使用instr函数处理
Declare
V_beg_date date := trunc(sysdate,’month’);
V_end_date date := trunk(sysdate);
V_cust_str varchar2(1000) := ‘客户1, 客户2, 客户3…’;
Begin
select * from t_order_cust
Where o_date between v_beg_date and v_end_date
And instr(v_cust_str like ,o_custome) >0
End;
这种处理方式的优缺点跟使用like相似, 同样由于对o_customer使用了函数, 导致该索引不可用, 函数索引同样也不适用于这种情况.
五, 方法4 使用内存表处理
我们知道, oracle, sqlserver等关系数据库最善于处理的数据类型是集合, 而不是单独的记录. 同样的100条记录, 如果逐条循环处理和批量处理其效率的差别将是几何单位的.
所以, 为了提高查询效率, 我们这里考虑将给定的客户字符串转变为一个集合或者临时表来处理. Oracle使用全局临时表和复杂数据类型集合来支持这一点.
这里我们介绍一下使用复杂数据类型集合来处理的方式.
首先我们定义一个复杂类型.
create or replace type ctl.type_jax_varc2tab is table of varchar2(2000);
然后定义一个函数实现将给定的字符串转换为嵌套内存表.
CREATEORREPLACEFUNCTION f_jax_str2tab(p_str INVARCHAR2,
p_sep varchar2default','
) RETURN ctl.type_jax_varc2tab IS
/******************************************************************
Ver1.0 Created by jaxzhang on 2009-06-08
把字符串(1*2*3*4*5)转换为内存表形式
create or replace type type_jax_varc2tab is table of varchar2(2000);
测试用例:SELECT * FROM TABLE(f_jax_str2tab('1*2*3*4*5','*'));
******************************************************************/
v_str varchar2(2000);
v_cnt NUMBER ;
v_numtab type_jax_varc2tab := type_jax_varc2tab(); --返回内存表
BEGIN
select decode(substr(p_str,-1),p_sep,p_str,p_str || p_sep) into v_str from dual;
select length(v_str) - length(REPLACE(v_str, p_sep)) into v_cnt from dual;
FOR i IN1 .. v_cnt LOOP
v_numtab.EXTEND;
v_numtab(i) := substr(v_str, 1, instr(v_str, p_sep) - 1);
v_str := substr(v_str, instr(v_str,p_sep) + 1);
ENDLOOP;
RETURN v_numtab;
EXCEPTION
WHENOTHERSTHEN
v_numtab.DELETE;
END;
上述函数的功能就是要将类似于’客户1,客户2,客户3’的字符串转换为如下形式.
SELECT * FROMTABLE(f_jax_str2tab('客户1,客户2,客户3',','));
COLUMN_VALUE |
客户1 |
客户2 |
客户3 |
得到上述的内存表之后, 我们就可以使用类似于一个表或者视图的方式来与正式表t_order_cust关联得到我们需要的查询结果.
Select /*+ ordered use_nl(a b)*/
From TABLE(f_jax_str2tab('客户1,客户2,客户3',',')) a,
T_order_cust b
Where b.o_customer = a.column_value

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









Oracleのソリューションを開くことはできません。1。データベースサービスを開始します。 2。リスナーを開始します。 3.ポートの競合を確認します。 4.環境変数を正しく設定します。 5.ファイアウォールまたはウイルス対策ソフトウェアが接続をブロックしないことを確認してください。 6.サーバーが閉じているかどうかを確認します。 7. RMANを使用して破損したファイルを回復します。 8。TNSサービス名が正しいかどうかを確認します。 9.ネットワーク接続を確認します。 10。Oracleソフトウェアを再インストールします。

Oracleのすべてのデータを削除するには、次の手順が必要です。1。接続を確立します。 2。外部のキーの制約を無効にします。 3.テーブルデータを削除します。 4.トランザクションを送信します。 5.外部キーの制約を有効にします(オプション)。データの損失を防ぐために、実行前にデータベースを必ずバックアップしてください。

Oracle Cursorの閉鎖問題を解決する方法には、次のものが含まれます。 Scopeが終了した後に自動的に閉じるように、for update句のカーソルを宣言します。使用句のカーソルを宣言して、関連するPL/SQL変数が閉じられたときに自動的に閉じるようにします。例外処理を使用して、例外の状況でカーソルが閉じていることを確認します。接続プールを使用して、カーソルを自動的に閉じます。自動送信を無効にし、カーソルの閉鎖を遅延させます。

Oracleでは、forループループは動的にカーソルを作成できます。手順は次のとおりです。1。カーソルタイプを定義します。 2。ループを作成します。 3.カーソルを動的に作成します。 4。カーソルを実行します。 5。カーソルを閉じます。例:カーソルをサイクルごとに作成して、上位10人の従業員の名前と給与を表示できます。

Oracle Database Pagingは、Rownum Pseudo-ColumnsまたはFetchステートメントを使用して実装しています。RownumPseudo-Columnsは、行番号ごとに結果をフィルタリングするために使用され、複雑なクエリに適しています。 Fetchステートメントは、指定された最初の行を取得するために使用され、単純なクエリに適しています。

Oracleデータベースを停止するには、次の手順を実行します。1。データベースに接続します。 2。すぐにシャットダウンします。 3.シャットダウンは完全に中止します。

SQLステートメントは、Oracleの動的SQLを使用して、ランタイム入力に基づいて作成および実行できます。手順には、次のものが含まれます。動的に生成されたSQLステートメントを保存するための空の文字列変数を準備します。 executeを即座に使用するか、ステートメントを準備して、動的なSQLステートメントをコンパイルおよび実行します。バインド変数を使用して、ユーザー入力またはその他の動的値を動的SQLに渡します。実行するか、実行するか、動的SQLステートメントを実行します。

CENTOSシステムにHadoop分散ファイルシステム(HDFS)を構築するには、複数のステップが必要です。この記事では、簡単な構成ガイドを提供します。 1.初期段階でJDKをインストールする準備:すべてのノードにJavadevelopmentKit(JDK)をインストールすると、バージョンはHadoopと互換性がある必要があります。インストールパッケージは、Oracleの公式Webサイトからダウンロードできます。環境変数構成: /etc /プロファイルファイルを編集し、JavaおよびHadoop環境変数を設定して、システムがJDKとHadoopのインストールパスを見つけることができるようにします。 2。セキュリティ構成:SSHパスワードなしログインSSHキーを生成する:各ノードでSSH-KeyGenコマンドを使用する
