# 삭제된 게시물을 일괄적으로 영구 삭제할 수 있나요?

**URL:** https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289
**Category:** Support
**Created:** [9월 12, 2021, 4:15오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289 "2021-09-12T04:15:12Z")
**Posts on this page:** 20
**Page:** 3

<div class="post-metadata">

### Author: ![IAmGav](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/iamgav/32/235598_2.png) [@IAmGav](https://meta.discourse.org/u/IAmGav)
#### Post date: [11월 3, 2021, 5:46오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/41 "2021-11-03T05:46:11Z")

</div>

기억이 맞다면 deleted\_at이라는 필드가 있습니다.

삭제된 경우라면 날짜와 시간 스탬프가 있어야 합니다.

삭제되지 않은 경우라면 null입니다.

null이 아닌 항목을 찾아 삭제하는 방법을 살펴보시는 것이 좋습니다.

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [11월 3, 2021, 6:46오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/42 "2021-11-03T06:46:03Z")

</div>

> [@IAmGav](#):
>
> 아마도 \<\> Null인 항목을 찾아 삭제하면 될 것 같습니다.

Gav, 감사합니다. 하지만 제가 대상으로 삼고 있는 항목들은 삭제 처리가 되어 있지 않습니다. 오히려 해당 항목들의 Topic이 삭제된 후 `destroy_all`이 호출된 상태입니다.

---

<div class="post-metadata">

### Author: ![IAmGav](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/iamgav/32/235598_2.png) [@IAmGav](https://meta.discourse.org/u/IAmGav)
#### Post date: [11월 4, 2021, 10:00오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/43 "2021-11-04T10:00:04Z")

</div>

이것을 테스트해보다가 쿼리의 일부가 필요한 응답을 반환하지 않는다는 것을 발견했습니다.

`SELECT topic_id from posts`는 정수 대신 문자열을 반환합니다.

 ![image](https://global.discourse-cdn.com/meta/original/3X/9/e/9e4f85f607cde962bbfcffd05f3f1bca9c4294a3.png)

이것이 데이터베이스에 고아 포스트(orphaned posts)가 여전히 남아 있는 원인일 수 있습니다.

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [11월 18, 2021, 12:26오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/44 "2021-11-18T00:26:19Z")

</div>

> [@IAmGav](#):
>
> 정수를 반환하지 않지만, 문자열을 반환했습니다

[Data Explorer](https://meta.discourse.org/t/32566?silent=true)가 label이 topic\_id인 경우 정수를 자동으로 URL로 변환하고 있기 때문에, 그런 현상을 보고 계신 것 같습니다.

[Data Explorer](https://meta.discourse.org/t/32566?silent=true)에서 이 쿼리를 실행하면, 식별하려는 모든 게시글이 모두 조회됩니다(5,000개 이상):

```plaintext
SELECT id, topic_id
FROM posts
WHERE topic_id not in (select id from topics)
ORDER by id

```

Rails 구문을 잘못 작성하고 있는 것 같아, 다음과 같은 결과가 나옵니다:

```plaintext
[1] pry(main)> Target = Post.where('topic_id not in (select id from topics)')
=> []

```

누구든 제가 무엇을 잘못하고 있는지 알려주실 수 있을까요?

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [11월 27, 2021, 2:12오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/45 "2021-11-27T02:12:28Z")

</div>

음, @pfaffman 덕분에 다음 코드를 사용하여 관련 게시물을 식별했습니다:

```plaintext
Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")

```

다음과 같은 출력을 얻습니다:

> [1] pry(main)\> Post.find\_by\_sql(“select id from posts where topic\_id not in (select id from topics)”)  
> =\> [#\<Post:0x000055df30d4ee90 id: 150\>,  
> #\<Post:0x000055df2e538ff0 id: 51097\>,  
> #\<Post:0x000055df2e50ba28 id: 83\>,  
> #\<Post:0x000055df2e4ee8b0 id: 40636\>,  
> #\<Post:0x000055df2e4a92d8 id: 62562\>,  
> #\<Post:0x000055df2e4b7978 id: 13522\>,  
> etc

그러나 이 선택된 항목에 `destroy_all`을 적용하는 방법을 알 수 없습니다.

(제 이해를 돕기 위해) 다음 링크가 도움이 될 수 있습니다:

> **[The Where Subquery - Advanced Active Record: Using Subqueries in Rails](https://pganalyze.com/blog/active-record-subqueries-rails#the-where-subquery)**
>
> Active Record provides a great balance between the ability to perform simple queries simply, and also the ability to access the raw SQL sometimes required to get our jobs done. In this article, we will see a number of real-life examples of business...

어떤 제안이 있을까요?

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [11월 27, 2021, 11:35오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/46 "2021-11-27T11:35:26Z")

</div>

이렇게 하면 될 것 같습니다

```plaintext
posts=
Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")

posts.destroy_all

```

아니면 `find_by_sql`에 `.destroy_all`을 추가할 수도 있습니다

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [11월 28, 2021, 12:45오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/47 "2021-11-28T00:45:06Z")

</div>

그 방법을 시도해 봤습니다. 데이터는 어떤 게시식 식별자와 ID를 가진 배열로 반환되는 것 같습니다 ([Delete deleted-posts permanently in bulk? - #45 by nathank](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/45) 참고).

`.destroy_all`을 추가하거나 제안해 주신 `posts=`를 사용할 때 발생하는 오류입니다:

> [2] pry(main)\> posts.destroy\_all  
> NoMethodError: undefined method `destroy_all' for #<Array:0x000055fe7bc7fc98> from (pry):3:in ` **pry** ’

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [11월 28, 2021, 1:03오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/48 "2021-11-28T01:03:41Z")

</div>

아. 그렇다면

```
 p=posts.first

```

이 post\_id인지 확인해 보세요. 맞다면 다음과 같이 하면 됩니다:

```
x=Post.find(p)
x.destroy

```

그 후 이 항목들을 반복문으로 처리할 수 있습니다.

쿼리를 무엇으로 감싸야 post id 배열이 아닌 post 배열을 얻을 수 있는지 확인해야 할 것 같습니다.

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [11월 28, 2021, 4:20오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/49 "2021-11-28T04:20:11Z")

</div>

Jay, 감사합니다. 이렇게 나옵니다:

> [3] pry(main)\> p=  
> [3] pry(main)\* posts.first  
> =\> #\<Post:0x0000563a24cab908 id: 150\>  
> [4] pry(main)\> x=Post.find(p)  
> ArgumentError: You are passing an instance of ActiveRecord::Base to `find`. Please pass the id of the object by calling `.id`.  
> from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active\_record/relation/finder\_methods.rb:467:in `find\_one’

> [@pfaffman](#):
>
> 포스트 ID 배열이 아니라 포스트 배열을 얻으려면 쿼리를 무엇으로 감싸야 할 것 같습니다.

자, 이 'wrap’이라는 것에 대해 알려주세요. @Sam의 이 rails 명령어는 작동해야 한다고 생각하는데, 그때 이후로 Rails가 변경된 것 같아 정말 짜증납니다:

> [@Sam](#):
>
> `Post.where('topic_id not in (select id from topics)').limit(100).destroy_all`

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [11월 28, 2021, 9:30오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/50 "2021-11-28T09:30:44Z")

</div>

그게 뭘 한 거예요? 레일스가 바뀌었을 리가 없다고 생각해요.

---

<div class="post-metadata">

### Author: ![pfaffman](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pfaffman/32/120154_2.png) [@pfaffman](https://meta.discourse.org/u/pfaffman)
#### Post date: [11월 28, 2021, 11:29오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/51 "2021-11-28T11:29:57Z")

</div>

> [@Sam](#):
>
> Post.where(‘topic\_id not in (select id from topics)’)

이 쿼리로 삭제하려는 게시글들을 가져올 수 있나요?

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [11월 28, 2021, 5:40오후 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/52 "2021-11-28T17:40:32Z")

</div>

> [@pfaffman](#):
>
> Rails가 변경되었다고 상상할 수 없군요.

Active Record 배열을 Active Record Relation으로 변환하는 방법에 대해 온라인에서 검색하던 중, Rails 3.x와 Rails 4 사이에서 변경 사항이 있었고 문법도 달라져야 한다는 내용을 어딘가에서 읽었습니다. 하지만 제게는 너무 어려워서 이해가 되지 않았습니다.

> [@pfaffman](#):
>
> 그렇게 하면 삭제하려는 게시글을 가져올 수 있나요?

처음 실행했을 때 몇 개를 가져오긴 해서, 당연히 `destroy_all`을 실행했습니다. 하지만 그 수가 많지 않았습니다. 지금은 전혀 가져오지 못하는 반면, [Data Explorer](https://meta.discourse.org/t/32566?silent=true)에서 SQL을 실행하면 수천 개의 레코드가 조회됩니다.

이것들은 Topic이 `Destroy_all`로 삭제된 후 남게 된 고아(Orphaned) Posts입니다.

---

<div class="post-metadata">

### Author: ![Simon\_Manning](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon_manning/32/198596_2.png) [@Simon\_Manning](https://meta.discourse.org/u/Simon_Manning)
#### Post date: [11월 28, 2021, 6:24오후 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/53 "2021-11-28T18:24:14Z")

</div>

`each{}`를 사용하여 해당 배열의 멤버를 반복하면서 각 게시글에 대해 개별적으로 `destroy`를 호출할 수 있나요?

```plaintext
Post.find_by_sql(“select id from posts where topic_id not in (select id from topics)”).each { |p| p.destroy }

```

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [12월 6, 2021, 8:28오전 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/54 "2021-12-06T08:28:09Z")

</div>

> [@Simon\_Manning](#):
>
> 해당 배열의 멤버를 반복하기 위해 `each{}`를 사용할 수 있나요?

음, 시도해 봤습니다. 처음에는 그렇게 감싸놓은 SQL도, 문법도 인정하지 않았습니다:

> Post.find\_by\_sql(“select id from posts where topic\_id not in (select id from topics)”).each { |p| p.destroy\_all }  
> SyntaxError: unexpected `in’, expecting ‘(’  
> …rom posts where topic\_id not in (select id from topics)”)…  
> … ^~  
> SyntaxError: unexpected local variable or method, expecting end-of-input  
> …t in (select id from topics)”).each { |p| p.destroy\_all }

그래서 나누어 처리하는 또 다른 어설픈 방법을 시도해 봤습니다:

```plaintext
posts=Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")
posts.each do |p|
p.destroy
end

```

이것은 잘 실행되는 것 같았지만, `p.destroy`를 추가하면 다음과 같은 오류가 발생합니다:

> ActiveModel::MissingAttributeError: missing attribute: user\_id  
> from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activemodel-6.1.4.1/lib/active\_model/attribute.rb:222:in `value’

여러 방법으로 그 값을 넣으려 해 보았지만 결국 포기했습니다. @sam, 도와주실 수 있나요?

### P.S.

다음과 같은 내용으로 SQL을 AR로 변환해 보려고 scuttle.io를 시도해 보았습니다:

```plaintext
Post.select([:id, :topic_id]).where(Topic.select(:id))

```

불행히도 다음과 같은 오류가 발생합니다:

> ArgumentError: Unsupported argument type: #Topic::ActiveRecord\_Relation:0x000055c67a7131d0 (Topic::ActiveRecord\_Relation)

---

<div class="post-metadata">

### Author: ![Simon\_Manning](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon_manning/32/198596_2.png) [@Simon\_Manning](https://meta.discourse.org/u/Simon_Manning)
#### Post date: [12월 6, 2021, 1:18오후 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/55 "2021-12-06T13:18:08Z")

</div>

> [@nathank](#):
>
> 음, 한번 시도해 봤습니다. 처음에는 그렇게 감싸서 쓴 SQL도, 구문도 마음에 들어하지 않았습니다:

이전 메시지 일부에서 그 부분을 복사해서 붙여넣었는데, 어딘가에서 따옴표가 곡선 따옴표(curly quotes)로 변환된 것 같습니다. 아마 그게 실제 오류일 것 같습니다. 죄송합니다.

> [@nathank](#):
>
> 이건 정상적으로 실행된 것 같은데, `p.destroy`를 추가하면 이런 오류가 납니다:
> 
> > ActiveModel::MissingAttributeError: missing attribute: user\_id  
> > from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activemodel-6.1.4.1/lib/active\_model/attribute.rb:222:in `value’

`find_by_sql`은 SQL 쿼리에 지정된 값을 가진 객체를 반환한다고 설명되어 있는데, 이는 `id` 속성만 설정된 Post 객체를 반환받고, `user_id`와 그 외 모든 값이 누락되어 있다는 것을 의미합니다.

`... find_by_sql("select * ...`는 이 문제를 해결해 줄 것입니다. 모든 것을 선택하는 대신 destroy를 수행할 수 있는 값의 부분 집합을 선택할 수도 있을 것 같지만, 그 부분 집합이 무엇인지는 제가 알지 못합니다.

그래서 전체 코드는 다음과 같습니다: (이번에는 곡선 따옴표 없이…)

```plaintext
Post.find_by_sql("select * from posts where topic_id not in (select id from topics)").each { |p| p.destroy }

```

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [12월 6, 2021, 7:34오후 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/56 "2021-12-06T19:34:28Z")

</div>

> [@Simon\_Manning](#):
>
> `Post.find_by_sql("select * from posts where topic_id not in (select id from topics)").each { |p| p.destroy }`

# 🥳 할렐루야!!! 🥳

Simon 감사합니다 - 정말 완벽하게 작동했습니다. 고아 포스트가 모두 사라졌고, 앞으로 24시간 정도 동안 업로드 용량이 거의 0에 가까워지는 것을 기대하고 있습니다.

_나중에_  
역시 그랬습니다! 3.5GB에서 0.7GB로 줄었습니다. 최고!!

---

<div class="post-metadata">

### Author: ![Simon\_Manning](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon_manning/32/198596_2.png) [@Simon\_Manning](https://meta.discourse.org/u/Simon_Manning)
#### Post date: [12월 8, 2021, 4:00오후 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/57 "2021-12-08T16:00:57Z")

</div>

좋습니다, 도움이 되었다니 기쁩니다. 답변을 통합하기 위해, 90일 이상 삭제된 모든 주제를 삭제하려면 다음 명령을 Rails 콘솔에서 사용할 수 있습니다. 주제가 1000개 이상이라면 필요한 만큼 반복하세요:

```plaintext
Topic.with_deleted.where(deleted_at: ...90.days.ago).limit(1000).destroy_all

```

이 작업이 완료된 후, 삭제된 주제에서 고아가 된 모든 게시물을 삭제하려면 다음을 사용할 수 있습니다:

```plaintext
Post.find_by_sql("select * from posts where topic_id not in (select id from topics)").each { |p| p.destroy }

```

위 명령들은 삭제된 게시물은 삭제하지 않으며, 삭제된 주제와 그 고아 게시물만 삭제한다는 점에 유의해야 합니다. 90일 이상 삭제된 게시물도 함께 삭제하려면 다음을 사용하세요. 마찬가지로 필요한 만큼 반복하세요:

```plaintext
Post.with_deleted.where(deleted_at: ...90.days.ago).limit(1000).destroy_all

```

**참고.** 참고로, `limit(1000)` 없이 `destroy_all`을 시도해 보셨나요? 문제가 있었나요, 아니면 제한 없이 시도해 보지 않으셨나요?

---

<div class="post-metadata">

### Author: ![nathank](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nathank/32/290039_2.png) [@nathank](https://meta.discourse.org/u/nathank)
#### Post date: [12월 8, 2021, 9:29오후 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/58 "2021-12-08T21:29:17Z")

</div>

> [@Simon\_Manning](#):
>
> **P.S.** 궁금해서 여쭤봅니다. `limit(1000)` 없이 `destroy_all`을 시도해 보셨나요? 그렇게 했을 때 문제가 발생했는지, 아니면 limit 없이 시도조차 안 해보셨는지요?

limit 없이 시도해 보았는데 뭔가 좀 이상하게 동작하더라고요 - 하지만 자세한 내용은 기억이 나지 않네요. 죄송합니다.

질문자님의 게시물을 해결책으로 표시하거나 OP의 내용을 사용해도 될까요?

![image](https://global.discourse-cdn.com/meta/original/3X/f/c/fccc6d8c640aa8190c0ff76caa7ea312ce84cf0d.png)

---

<div class="post-metadata">

### Author: ![Simon\_Manning](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon_manning/32/198596_2.png) [@Simon\_Manning](https://meta.discourse.org/u/Simon_Manning)
#### Post date: [12월 9, 2021, 11:26오후 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/59 "2021-12-09T23:26:54Z")

</div>

걱정하지 마세요. 만약 시도해 보지 않으셨다면, 한도 설정이 필요하지 않을 수도 있다는 주석을 달았을 텐데, 문제가 있었으니 그대로 두겠습니다.

---

<div class="post-metadata">

### Author: ![system](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/system/32/443519_2.png) [@system](https://meta.discourse.org/u/system)
#### Post date: [1월 8, 2022, 11:26오후 UTC](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/60 "2022-01-08T23:26:59Z")

</div>

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.

[이전 페이지](https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289.md?page=2)
