Oracle クエリを最適化するにはどうすればよいですか?

coldplay.xixi
リリース: 2020-07-17 15:43:12
オリジナル
3920 人が閲覧しました

Oracle クエリ最適化方法: 1. UNION 演算子はテーブルのリンク後に生成された結果セットを並べ替え、重複レコードを削除して結果を返します; 2. 大なり小なり演算子の一般的な状況インデックスがあるためインデックス検索を使用しますが、場合によっては最適化できる場合があるため、以下を調整します。

Oracle クエリを最適化するにはどうすればよいですか?

Oracle クエリ最適化方法:

1.IN 演算子

IN で記述された SQL の利点は、記述が容易で明確で理解しやすいことであり、現代のソフトウェア開発のスタイルにより適しています。

ただし、IN を使用した SQL のパフォーマンスは常に比較的低く、ORACLE によって実行される手順から、IN を使用した SQL と IN を使用しない SQL には次の違いがあります。

##ORACLE は、それを複数のテーブルの接続に変換しようとします。変換が失敗した場合は、最初に IN のサブクエリが実行され、次に外部テーブルのレコードがクエリされます。変換が成功した場合は、 、複数のテーブルの接続が直接使用されます。メソッドクエリ。 IN を使用する SQL には少なくとも 1 つ以上の変換プロセスがあることがわかります。一般的な SQL は正常に変換できますが、グループ統計などを含む SQL は変換できません。

関連する学習の推奨事項:

oracle データベース学習チュートリアル

2. NOT IN 演算子

この操作は強く推奨されます 使用されませんテーブルインデックスを適用できないためです。

推奨される解決策:

3, < の代わりに NOT EXISTS または (外部接続が空であると判断される) 解決策を使用してください。 ;> 操作 演算子 (等しくない)

等しくない演算子はインデックスを使用しないため、その処理ではテーブル全体のスキャンのみが行われます。

推奨される解決策: 代わりに、同じ関数を持つ他の演算を使用してください。たとえば、

a<>0 が a>0 に変更される、またはa< 0

a<>'' は、a>''

4、>、および < に変更されます。演算子 ( 大なり演算子または小なり演算子)

大なり演算子または小なり演算子は、インデックスがあるためインデックス検索を使用するため、通常は調整する必要はありませんが、場合によっては、テーブルには 100 万件のレコードがあり、数値フィールドには A、300,000 件のレコードには A=0、300,000 件のレコードには A=1、390,000 件のレコードには A=2、10,000 件のレコードには A=3 などの最適化が可能です。次に、A>2 と A>=3 の実行の効果には大きな違いがあります。A>2 の場合、ORACLE は最初に 2 のレコード インデックスを見つけて比較しますが、A>=3 の場合、ORACLE は直接レコード インデックスを検索します。 find = 3 レコードのインデックス。

5. IS NULL または IS NOT NULL 操作 (フィールドが空かどうかの判断)

一般に、フィールドが空かどうかの判断は、 B ツリー インデックスは NULL 値にインデックスを付けないため、インデックスが付けられます。

推奨される解決策:

同じ機能を持つ他の操作 (

など) に置き換えます。 a が null ではない場合は、a>0 または a>'' などに変更されます。

フィールドを空にすることはできず、空の値を置き換えるためにデフォルト値が使用されます。たとえば、業界拡張アプリケーションのステータス フィールドを空にすることはできません。 、デフォルトはアプリケーションです。

ビットマップ インデックスを作成します (パーティション テーブルは構築できません。ビットマップ インデックスは制御が困難です。インデックスに含まれるフィールド値が多すぎると、パフォーマンスが低下します。複数人で更新操作を行うと、データ ブロックの数を増やす。ロック現象)

6. UNION 演算子

UNION はテーブルのリンク後に重複レコードを除外します。テーブルのリンク 生成された結果セットは並べ替えられ、重複レコードが削除されて、結果が返されます。実際のアプリケーションでは、重複レコードはほとんど生成されませんが、最も一般的なのはプロセス テーブルと履歴テーブル間の UNION です。例:

select * from gc_dfys union select * fromls_jg_dfys
ログイン後にコピー

この SQL は、実行時にまず 2 つのテーブルの結果を取り出し、次に並べ替えスペースを使用して重複レコードを並べ替えて削除し、最後に結果セットを返します。テーブルのデータが大きいため、ディスクによるソートが発生する可能性があります。

推奨される解決策: UNION ALL 演算は単純に 2 つの結果をマージした後に返すため、UNION の代わりに UNION ALL 演算子を使用します。

7. WHERE 句の後の条件の順序は、大規模なデータ スケールのクエリに直接影響します。

Select * from zl_yhjbqk where dy_dj =‘1KV以下‘ and xh_bz=1
 
Select * from zl_yhjbqk where xh_bz=1 and dy_dj =‘1KV以下‘
ログイン後にコピー

など 上記 2 つの SQL では、dy_dj (電圧レベル) と xh_bz (キャンセルフラグ) の 2 つのフィールドにインデックスが付けられていないため、実行中にテーブル全体がスキャンされます。レコード セットの最初の SQL における dy_dj = 'below 1KV' 条件の比率は 99% ですが、xh_bz=1 の比率はわずか 0.5% です。最初の SQL が実行されると、レコードの 99% が dy_dj と xh_bz です。 2 番目の SQL を比較すると、レコードの 0.5% が dy_dj および xh_bz と比較されており、このことから、2 番目の SQL の CPU 使用率は最初の SQL よりも大幅に低いと結論付けることができます。

8. 目標に関するヒント:

##COST (コストによる最適化)

RULE (ルールによる最適化)
  • CHOOSE (デフォルト) (ORACLE は最適化のためのコストまたはルールを自動的に選択します)
  • ALL_ROWS (所有的行尽快返回)

  • FIRST_ROWS (第一行数据尽快返回)

9、执行方法的提示:

  • USE_NL (使用 NESTED LOOPS 方式联合)

  • USE_MERGE (使用 MERGE JOIN 方式联合)

  • USE_HASH (使用 HASH JOIN 方式联合)

10、索引提示:

INDEX ( TABLE INDEX)(使用提示的表索引进行查询)

11、其它高级提示(如并行处理等等)

ORACLE 的提示功能是比较强的功能,也是比较复杂的应用,并且提示只是给ORACLE执行的一个建议,有时如果出于成本方面的考虑 ORACLE也可能不会按提示进行。根据实践应用,一般不建议开发人员应用ORACLE提示,因为各个数据库及服务器性能情况不一样,很可能一个地方性能提升了,但另一个地方却下降了,ORACLE 在 SQL执行分析方面已经比较成熟,如果分析执行的路径不对首先应在数据库结构(主要是索引)、服务器当前性能(共享内存、磁盘文件碎片)、数据库对象(表、索引)统计信息是否正确这几方面分析。

12、IN和EXISTS

有时候会将一列和一系列值相比较。最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询。

第一种格式是使用IN操作符:

... where column in(select * from ... where...);
ログイン後にコピー

第二种格式是使用EXIST操作符:

... where exists (select &#39;X&#39; from ...where...);
ログイン後にコピー

我相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第一种格式的效率高。在Oracle中可以几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。

第二种格式中,子查询以'select 'X'开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。

通过使用EXIST,Oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。Oracle系统在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。

同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查询效率更高。

任何在where子句中使用is null或is notnull的语句优化器是不允许使用索引的。

13、order by语句

ORDER BY语句决定了Oracle如何将返回的查询结果排序。Orderby语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Orderby语句的非索引项或者有计算表达式都将降低查询速度。

仔细检查orderby语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写orderby语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在orderby子句中使用表达式。

14、NOT

我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子:

... where not (status =&#39;VALID&#39;)
ログイン後にコピー

如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中,这就是不等于(<>)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例:

... where status <>&#39;INVALID&#39;;
ログイン後にコピー

再看下面这个例子:

select * from employee where salary<>3000;
ログイン後にコピー

对这个查询,可以改写为不使用NOT:

select * from employee where salary<3000 orsalary>3000;
ログイン後にコピー

虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。

全表扫描就是顺序地访问表中每条记录.ORACLE采用一次读入多个数据块(databaseblock)的方式优化全表扫描。

15、使用DECODE函数来减少处理时间

使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表。例如:

SELECT COUNT(*),SUM(SAL)
FROM EMP
WHERE DEPT_NO = 0020
AND ENAME LIKE ‘SMITH%’;
ログイン後にコピー

你可以用DECODE函数高效地得到相同结果.

SELECT COUNT(DECODE(DEPT_NO,0020,’X’,NULL)) D0020_COUNT,
COUNT(DECODE(DEPT_NO,0030,’X’,NULL)) D0030_COUNT,
SUM(DECODE(DEPT_NO,0020,SAL,NULL)) D0020_SAL,
SUM(DECODE(DEPT_NO,0030,SAL,NULL)) D0030_SAL
FROM EMP WHERE ENAME LIKE ‘SMITH%’;
ログイン後にコピー

类似的,DECODE函数也可以运用于GROUP BY 和ORDER BY子句中.

16、用Where子句替换HAVING子句

避免使用HAVING子句, HAVING只会在检索出所有记录之后才对结果集进行过滤.这个处理需要排序,总计等操作.如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销.例如:

  低效:

SELECT REGION,AVG(LOG_SIZE)
FROM LOCATION
GROUP BY REGION
HAVING REGION REGION != ‘SYDNEY’
AND REGION != ‘PERTH’
ログイン後にコピー

  高效:

SELECT REGION,AVG(LOG_SIZE)
FROM LOCATION
WHERE REGION REGION != ‘SYDNEY’
AND REGION != ‘PERTH’
GROUP BY REGION
ログイン後にコピー

17、减少对表的查询

在含有子查询的SQL语句中,要特别注意减少对表的查询.例如:

  低效:

SELECT TAB_NAME
FROM TABLES
WHERE TAB_NAME = ( SELECT TAB_NAME
FROM TAB_COLUMNS
WHERE VERSION = 604)
AND DB_VER= ( SELECT DB_VER
FROM TAB_COLUMNS
WHERE VERSION = 604)
ログイン後にコピー

  高效:

SELECT TAB_NAME
FROM TABLES
WHERE (TAB_NAME,DB_VER)
= ( SELECT TAB_NAME,DB_VER)
FROM TAB_COLUMNS
WHERE VERSION = 604)
Update 多个Column 例子:
ログイン後にコピー

  低效:

UPDATE EMP
SET EMP_CAT = (SELECT MAX(CATEGORY) FROM EMP_CATEGORIES),
SAL_RANGE = (SELECT MAX(SAL_RANGE) FROM EMP_CATEGORIES)
WHERE EMP_DEPT = 0020;
ログイン後にコピー

  高效:

UPDATE EMP
SET (EMP_CAT, SAL_RANGE)
= (SELECT MAX(CATEGORY) , MAX(SAL_RANGE)
FROM EMP_CATEGORIES)
WHERE EMP_DEPT = 0020;
ログイン後にコピー

18、通过内部函数提高SQL效率.

SELECT H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC,COUNT(*)
FROM HISTORY_TYPE T,EMP E,EMP_HISTORY H
WHERE H.EMPNO = E.EMPNO
AND H.HIST_TYPE = T.HIST_TYPE
GROUP BY H.EMPNO,E.ENAME,H.HIST_TYPE,T.TYPE_DESC;
ログイン後にコピー

通过调用下面的函数可以提高效率.

FUNCTION LOOKUP_HIST_TYPE(TYP IN NUMBER) RETURN VARCHAR2
AS
TDESC VARCHAR2(30);
CURSOR C1 IS
SELECT TYPE_DESC
FROM HISTORY_TYPE
WHERE HIST_TYPE = TYP;
BEGIN
OPEN C1;
FETCH C1 INTO TDESC;
CLOSE C1;
RETURN (NVL(TDESC,’?’));
END;
FUNCTION LOOKUP_EMP(EMP IN NUMBER) RETURN VARCHAR2
AS
ENAME VARCHAR2(30);
CURSOR C1 IS
SELECT ENAME
FROM EMP
WHERE EMPNO=EMP;
BEGIN
OPEN C1;
FETCH C1 INTO ENAME;
CLOSE C1;
RETURN (NVL(ENAME,’?’));
END;
SELECT H.EMPNO,LOOKUP_EMP(H.EMPNO),
H.HIST_TYPE,LOOKUP_HIST_TYPE(H.HIST_TYPE),COUNT(*)
FROM EMP_HISTORY H
GROUP BY H.EMPNO , H.HIST_TYPE;
ログイン後にコピー

以上がOracle クエリを最適化するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート