最直觀的方法就是`delete`,但這種方法效率不好,而且可能data被其它session擋住,解法為(oracle db適用):
:bulb::bulb::bulb: **將DML操作改為DDL操作**
1. 移除全部內容:`truncate`
2. 使用`create-table-as-select` 移除大部分的data
3. `drop`或`truncate` patition
4. 使用filtered table move
---
### DML statement 刪除rows
```sql
delete from table where status = "expired"
```
### 1. 移除全部內容:`truncate`
即時的metadata操作,預設會在最小區段(minextents)下重置space,可以透過storage clause改變行為
- truncate table ... reuse storage leaves all the space allocated to the table
- truncate table ... drop storage(the default) deallocates all the space above the minextents for the table
- truncate table ... drop all storage deallocates all space from the table
```sql
-- 使用前需要確認無FK關聯的table,即使關聯table為空仍會拋錯
truncate table tableTable;
-- ORA-02266: unique/primary keys in table referenced by enabled foreign keys
-- 修正方案, 關聯table須為空, 否則無法重驗證FK
alter table to_empty_it_child
modify constraint fk disable;
truncate table to_empty_it;
alter table to_empty_it_child
modify constraint fk enable;
-- 關聯table也要一併刪除
truncate table to_empty_it
cascade;
```
### 2. 使用create -table-as-select(CTAS)法移除rows
<!--bear with me, be patient -->
:zany_face: insert資料比刪除還要快速,在刪除大量records時可以使用:
- 建立新的table, 將欲保留的records存在這裡
- truncate原先table
- 回存資料至原先table
:zany_face: 類似方式,可以刪除舊表再直接更名新表
- 建立新的table, 將欲保留的records存在這裡
- drop or rename 舊表
- rename新table成原本的table name
```sql
-- 回存資料
create table rows_to_keep
select * from massive_table
where save_these = 'Y';
truncate table massive_table;
insert into massive_table
select * from rows_to_keep;
-- 換表更名, 只load data一次, 所以更快一些
create table rows_to_keep
select * from massive_table
where save_these = 'Y';
rename massive_table
to massive_archived;
rename rows_to_keep
to massive_table;
```
※ indexes, constraint, grant等都要記得複製過去, 此類步驟較花費時間, 要測試哪種ctas方法整體較有效率
※ 各種相依性使其有點fiddly, 最好離線狀態處理
### 3. 移除table的特定partition(sub-table)
- table已事先進行partition
- 目的是移除特定partition的**全部**內容
```sql
-- 注意要先關閉關聯table的fk
alter table to_archive_from
drop partition to_remove_it;
alter table to_archive_from
truncate partition to_empty_it;
```
※ 此移除為例行性事務,否則做partion可能不符成本效益
※ partition影響各式操作,像key queries會變慢
### 4. 使用filter-table move 移除rows
通常`alter table … move`用來調整儲存的tablespace或是一些table的實體properties,如compression,屬於DDL操作,也能用來提升效能,移動重排處理records位置瑣碎分散的問題,沒被移動就是刪除 (oracle12.2+)
:telescope: 建議操作前離線備份: expdp
```sql
alter table to_delete_from
move including rows
where rows_to_keep = 'Y';
-- 如同truncate, 需注意 ORA-02266: unique/primary keys in table referenced by enabled foreign keys
```
---
綜合來說
--
delete DML做絕對是最慢的, CTAS跟filtered move表現佳,truncate partition則是在移除量少時表現較佳
:bookmark_tabs: REF
---
- [How to Delete Millions of Rows Fast with SQL](https://blogs.oracle.com/sql/post/how-to-delete-millions-of-rows-fast-with-sql)
- [Remove Billions of Rows Really Fast...](https://www.linkedin.com/pulse/remove-billions-rows-really-fast-johny-perapras/)