查看完整版本: 同樣是資料庫 delete 的話題
頁: [1]

hsw1976 發表於 2016-3-19 04:44 AM

同樣是資料庫 delete 的話題

各位來討論看看

相信大家一定都在專案裡做過需要做多筆刪除的機制
而實現多筆刪除的方式,歸納起來也就只有兩種

第一種是循環敘述法,也就是藉由網頁程式的迴圈來跑刪除的SQL敘述 (刪幾筆資料,網頁程式就處理SQL請求幾次)

第二種是鍵值集合法,也就是用 SQL 敘述的 IN 來達成效果。 (網頁程式端只需要執行一次處理SQL的請求)

你們比較偏好使用哪種方式?
<div></div>

sheauren 發表於 2016-3-20 10:22 PM

這我是看資料量跟速度要求來評估
1. 刪除筆數不多、速度不講究、刪除規則複雜的,優先考慮用程式端來控制刪除,未來接手的人會比較看得懂。

2. 刪除資料筆數太多、刪除規則簡單、效能需求的情況下,就會考慮直接用SQL來做,但是用IN的話,我記得超過一定筆數好像撐不住....

最好的方式是搞出一個好一點的codition,盡量不要用where in的方式,靠sql能直接整批刪除最好。
所以為此有時候常需要刪除的table schema會建立副本的欄位(放棄第三正規化),讓select/update/delete的語法簡化...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

hsw1976 發表於 2016-3-21 02:47 AM

sheauren 發表於 2016-3-20 10:22 PM static/image/common/back.gif
這我是看資料量跟速度要求來評估
1. 刪除筆數不多、速度不講究、刪除規則複雜的,優先考慮用程式端來控制刪 ...

IN 確實是會有效能問題,一般為了效能考量,也都會設法拆成獨立的 SQL 敘述

突然想到還有一種方式:欄位標記法。

也就是不在資料庫端下 DELETE 這種 SQL 敘述。而是在 Table 有個「是否顯示」的欄位,1 (true) 要顯示,0 (false) 不顯示。

若是未刪除的資料,就 Where 欄位值為 1 (true) 篩選到列表上;用戶端若操作刪除,就把此欄位值 Update 為 0 (false)。...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

sheauren 發表於 2016-3-21 07:46 AM

hsw1976 發表於 2016-3-21 02:47 AM static/image/common/back.gif
IN 確實是會有效能問題,一般為了效能考量,也都會設法拆成獨立的 SQL 敘述

突然想到還有一種方式:欄位 ...

有種有delete_flag的感覺,
不過要看該資料是否有保存必要跟table資料量是否很大才能評估要不要這麼用...
如果該資料刪除會影響到資料完整性的,就會多一個刪除記號,
例如:acitve_yn varchar(1) /* Y='生效',N='失效',D='刪除'*/
不過這也是當初評估資料量不會太誇張,而且有資料恢復需求,才敢這麼設計。
不然既然可以update flag,直接刪除舊好了。
而且資料數量越大join起來就越刺激。
以前有遇過FA的oracle db,sql query超過幾秒就被dba設定ban掉,
where條件[>...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

theloserbm 發表於 2016-3-21 11:17 AM

我待過的2家公司都是跑delete_flag的路線, 因為有個紀錄還是保險些.
如果真的要刪, 就是用迴圈那個而已, 不過是在server端(PHP等)做, 網頁端(JS)只發送一次請求.

看你的敘述好像也能夠寫成IN的批次迴圈, 就是集合例如20筆一起用IN刪除.
話說你們有做cascade delete的嗎? 這個用IN來做會比較快?<br><br><br><br><br><div></div>

hsw1976 發表於 2016-5-7 11:52 PM

theloserbm 發表於 2016-3-21 11:17 AM static/image/common/back.gif
我待過的2家公司都是跑delete_flag的路線, 因為有個紀錄還是保險些.
如果真的要刪, 就是用迴圈那個而已, 不 ...

cascade delete? 串接式刪除法?這是什麼概念?能否介紹一下?


補充內容 (2016-5-14 01:10 PM):
感覺有點像Master-detail結構常見的模式,刪除 master 時,透過條件約束連同 detail 也一併刪除

補充內容 (2016-5-14 01:16 PM):
這個機制好像在 SQL Server 2000 時代就有,還有個專稱,不過忘了叫什麼,印象中都是四個字...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

chevylin0802 發表於 2016-5-8 12:47 AM

本帖最後由 chevylin0802 於 2016-5-8 12:49 AM 編輯

就我所知道的國外行業的習慣
並不會把SQL的語法直接曝露在server上的腳本程式裏
這裏所指的腳本程式可能是JAVA, PHP, Python或者是其他
通常都會採取呼叫Store Procedure的執行方式
至於Store Procedure裏面怎麼寫
就成了資料庫設計師的Know How

基本上
在國外就連Modify一筆資料
都被視為新增一筆資料的方式在使用
以便留下所有更新前後的記錄
他們的觀念比較像會計學科所使用的借貸觀念
借方與貸方是分別記錄的
最終要使借方與貸方的數字總合一致

同樣的意思
刪除也被視為新增一筆資料

因此國外的資料庫設計往往都採取資料只能新增不能修改以及刪除的辦法
當然這也會造成在搜尋上的時間延遲
因此通常還有更深入的做法
在每日定期備份的時間裏
他們還會將資料再做一份有經歷過修改與刪除的資料表
用來加快搜尋速度的用途
或者是在進行刪除與修改的Store Procedure當中
提供一個只能作搜尋用的資料表供搜尋使用
甚至於每日備份的過程當中還會類似會計系統的過帳方式
重新計算過每一筆新增與修改以及刪除的資料
作為嚴密的資料保護
而這也就使得資料表的存取權限設定要非常有sense的人才會清楚如何使用


...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

hsw1976 發表於 2016-7-31 01:16 AM

theloserbm 發表於 2016-3-21 11:17 AM static/image/common/back.gif
我待過的2家公司都是跑delete_flag的路線, 因為有個紀錄還是保險些.
如果真的要刪, 就是用迴圈那個而已, 不 ...

話說你們有做cascade delete的嗎? 這個用IN來做會比較快?

這個機制其實很好用,但仔細回想起來
好像沒真正用在任何一個專案上
幾乎都是自己私下測試時玩玩

方便之處在於不用另外寫程式去維護 Master-Detail 之間的資料關聯
當然這個機制也並非完美
印象中,有多重參照的,這招好像就行不通

太久沒玩了,不知記憶是否有誤

...<div class='locked'><em>瀏覽完整內容,請先 <a href='member.php?mod=register'>註冊</a> 或 <a href='javascript:;' onclick="lsSubmit()">登入會員</a></em></div>

B1DE49FC 發表於 2016-8-3 10:21 PM

where in 會用到 range select
效能應該不會很高
好一點的作法是讓每筆資料都有 uniqe key 或是特殊的 condition
且這些 key / condition 都有建立 index

不然還有一個方法
就是將多個 delete SQL 塞在同一個 transaction 裡面
N 筆資料全部刪除以後再一同更新一次 index file
速度會快一些
頁: [1]