EDITORIAL
SQLのパフォーマンスの最適化は、データベース・ユーザーが直面しなければならない重要な問題であり、このセクションでは、これらは、このセクションでの議論の範囲に含まれない、SQLの書き込み、SQLのパフォーマンスの最適化にもデータベースの特定の機能の影響により焦点を当てて
効率的なクエリを使用します
- パラメータサブクエリは、代わりに使用するのに存在します
-- 使用EXISTS替代IN的建表语句
CREATE TABLE Class_A
(id char(1),
name varchar(30),
PRIMARY KEY(id));
CREATE TABLE Class_B
(id char(1),
name varchar(30),
PRIMARY KEY(id));
INSERT INTO Class_A (id, name) VALUES('1', '田中');
INSERT INTO Class_A (id, name) VALUES('2', '铃木');
INSERT INTO Class_A (id, name) VALUES('3', '伊集院');
INSERT INTO Class_B (id, name) VALUES('1', '田中');
INSERT INTO Class_B (id, name) VALUES('2', '铃木');
INSERT INTO Class_B (id, name) VALUES('4', '西园寺');
-- 性能慢的写法
SELECT * FROM Class_A WHERE id IN (SELECT id FROM Class_B);
-- 性能快的写法
SELECT * FROM Class_A WHERE EXISTS (SELECT * FROM Class_B WHERE Class_A.id = Class_B.id);
約2 EXISTSの使用のための高速化の理由:
- 接続はインデックス列(ID)を確立している場合、実際のテーブルクエリClass_Bをチェックしていない、あなただけがそれにインデックスを検討する必要があります
あなたが使用している場合限り、問い合わせ、テーブル全体をスキャンで使用するのと同じではありませんが終了します条件を満たすために、データの列に見られるような、存在しています。この時点では、あまりにも、EXISTSはありません。
パラメータは、代替接続を使用して、サブクエリです
-- 使用连接替代IN
SELECT Class_A.id,Class_A.name
FROM Class_A INNER JOIN Class_B
ON Class_A.id = Class_B.id;
順序を避けます
そして、異なる言語、SQL言語のためのプロセスが明示的にユーザーがデータベース操作を並べ替えることはできませんコマンド。しかし、ソート代表ソートの様々な実際のデータベースアンダーカバーは、次の操作を持っています。
- GROUP BY
- ORDER BY
- 集計関数(SUMのCOUNT AVG MIN MAX)
- DISTINCT
- 集合演算子(EXCEPT UNION INTERSECT)
窓関数(RANK ROW_NUMBER)
集合演算子の使用における柔軟性ALLオプション
-- 求所有的id和name
SELECT * FROM Class_A
UNION
SELECT * FROM Class_B;
-- 如果不在话是否有重复值,则可以使用ALL选项
SELECT * FROM Class_A
UNION ALL
SELECT * FROM Class_B;
次の表の各データベース・オプションのALLのサポート:
オラクル | DB2 | SQL Severを | PostgreSQLの | MySQLの | |
---|---|---|---|---|---|
連合 | ● | ● | ● | ● | ● |
INTERSECT | × | ● | × | ● | - |
EXCEPT | × | ● | × | ● | - |
- 使用して、EXISTSの代わりにDISTINCT
-- 使用EXISTS代替DISTINCT的建表语句
CREATE TABLE Items
(item_no INTEGER PRIMARY KEY,
item VARCHAR(32) NOT NULL);
INSERT INTO Items VALUES(10, 'FD');
INSERT INTO Items VALUES(20, 'CD-R');
INSERT INTO Items VALUES(30, 'MO');
INSERT INTO Items VALUES(40, 'DVD');
CREATE TABLE SalesHistory
(sale_date DATE NOT NULL,
item_no INTEGER NOT NULL,
quantity INTEGER NOT NULL,
PRIMARY KEY(sale_date, item_no));
INSERT INTO SalesHistory VALUES('2007-10-01', 10, 4);
INSERT INTO SalesHistory VALUES('2007-10-01', 20, 10);
INSERT INTO SalesHistory VALUES('2007-10-01', 30, 3);
INSERT INTO SalesHistory VALUES('2007-10-03', 10, 32);
INSERT INTO SalesHistory VALUES('2007-10-03', 30, 12);
INSERT INTO SalesHistory VALUES('2007-10-04', 20, 22);
INSERT INTO SalesHistory VALUES('2007-10-04', 30, 7);
-- 查找有销售记录的商品
SELECT Items.item_no
FROM Items INNER JOIN SalesHistory
ON Items.item_no = SalesHistory.item_no;
-- 去重(慢)
SELECT DISTINCT Items.item_no
FROM Items INNER JOIN SalesHistory
ON Items.item_no = SalesHistory.item_no;
-- 去重(快)
SELECT item_no FROM Items WHERE EXISTS (SELECT * FROM SalesHistory WHERE Items.item_no = SalesHistory.item_no);
- 極値指数関数を使用します
-- 这样写需要扫描全表
SELECT MAX(item) FROM Items;
-- 这样写可以用到索引
SELECT MAX(item_no) FROM items;
-- 这样写并不是渠道了排序过程,而是优化了排序前的查找速度
- HAVING句に書いていないWHERE句の条件に書き込むことができます
-- 聚合后使用HAVING子句过滤
SELECT sale_date,SUM(quantity)
FROM SalesHistory
GROUP BY sale_date
HAVING sale_date = '2007-10-01';
-- 聚合前使用WHERE子句过滤
SELECT sale_date,SUM(quantity)
FROM SalesHistory
WHERE sale_date = '2007-10-01'
GROUP BY sale_date;
-- 写法二效率更高的原因:GROUP BY聚合时会进行排序,如果事先通过WHERE子句筛选一部分,能够减轻排序的负担;WHERE子句的条件里可以使用索引,HAVING子句是针对聚合后生成的视图进行筛选的,但很多时候聚合后的视图并没有继承原表的索引结构
- BY句句とORDER BY GROUPのインデックスを使用します
本当にまだインデックスに使用されます
- インデックスフィールド上で操作するには
-- 没有使用到索引的情况
SELECT * FROM SomeTable
WHERE col_1 * 1.1 > 100;
-- 使用到索引的情况
SELECT * FROM SomeTable
WHERE col_1 > 100 / 1.1;
-- 左侧使用函数也用不到索引
SELECT * FROM SomeTable
WHERE SUBSTR(col_1,1,1) = 'a'; -- 使用索引时,条件表达式的左侧应该是原始字段
- 使用して、IS NULL述部
通常はNULLインデックスフィールドが存在しない、それはIS NULLを指定し、NULLではない、それはインデックスが悪いクエリのパフォーマンスにつながる、使用することはできないでしょう。
-- IS NULL没办法继续优化
SELECT * FROM SomeTable WHERE col_1 IS NULL;
-- IS NOT NULL时,修改成 > 一个比最小值还小的数
SELECT * FROM SomeTable WHERE col_1 > 0; -- 假设col_1最小值是1
- 負の形式を使用します
"<>" / "!=" /インデックス "にない" は使用されません
-- 全表扫描
SELECT * FROM SomeTable WEHRE col_1 <> 100;
-- 否定形式
SELECT * FROM SomeTable WHERE NOT (col_1 = 100);
- 使用しますか、
-- 用不到索引的情形
SELECT * FROM SomeTable WEHRE col_1 > 100 OR col_2 = 'abc';
- 組み合わせインデックス、列のエラーのために使用された場合
組み合わせたシーケンスインデックス「COL_1、col_2、col_3」があると仮定
SELECT * FROM SomeTable WHERE col_1 = 10 AND col_2 = 100 AND col_3 = 500; -- '●'
SELECT * FROM SomeTable WHERE col_1 = 10 AND col_2 = 100 -- '●'
SELECT * FROM SomeTable WHERE col_1 = 10 AND col_3 = 500; -- 'x'
SELECT * FROM SomeTable WHERE col_2 = 100 AND col_3 = 500; -- 'x'
SELECT * FROM SomeTable WHERE col_2 = 100 AND col_1 = 10; -- 'x'
- 同じに一致するように背後述語または中間一貫ように使用
唯一のフロントには、インデックスを使用するために一致しました
SELECT * FROM SomeTable WHERE col_1 LIKE '%a'; -- 'x'
SELECT * FROM SomeTable WHERE col_1 LIKE '%a%'; -- 'x'
SELECT * FROM SomeTable WHERE col_1 LIKE 'a%'; -- '●'
- 実行されるデフォルトの型変換
タイプCHAR「COL_1」を指定した条件の列の例
SELECT * FROM SomeTable WHERE col_1 = 10; -- 'X'
SELECT * FROM SomeTable WHERE col_1 = '10'; -- '●'
SELECT * FROM SomeTable WHERE col_1 = CAST(10,AS CHAR(2)); -- '●'
中間テーブルを削減
SQLでは、サブクエリは、限定することなく、中間パッケージの広範な使用は、性能低下の問い合わせになり、新たなテーブルとして見ることができます
- HAVING句の柔軟な使用
-- 无意义的中间表
SELECT * FROM
(SELECT sale_date,MAX(quantity) AS max_qty FROM SalesHistory GROUP BY sale_date) TMP
WHERE max_qty >= 10;
-- HAVING
SELECT * FROM SalesHistory GROUP BY sale_date HAVING MAX(quantity) >= 10;
- 述語のフィールドを複数使用する必要があり、それらはに集約されます
-- 多个字段使用IN
SELECT id,state,city FROM Address1 A1 WHERE state IN (SELECT state FROM Addresses2 A2 WHERE A1.id = A2.id) AND city IN (SELECT city FROM Addresses2 A2 WHERE A1.id = A2.id);
-- 通过字段连接(但可能带来类型转换问题,无法使用索引)
SELECT * FROM Addresses1 A1 WHERE id || state || city IN (SELECT id || state || city FROM Addresses2 A2);
-- 优化版本
SELECT * FROM Addresses1 A1 WHERE (id,state,city) IN (SELECT id,state,city FROM Addresses2 A2);
- さらに重合を接続するには
- 合理的な利用ビュー
セクションの概要
- パラメータサブクエリは、代わりに使用するのに存在します
- インデックスを使用する場合は、条件式の左辺は、元のフィールドでなければなりません
- SQLのソートでは明示的に指定され、多くのアンダーカバーの操作がソートされることに注意してくださいすることができません
- 無用中間テーブルの使用を最小限に抑えます