0

내 사용자 테이블에 열을 추가하고 모두에 대해 슬러그를 생성하고 싶습니다. 문제는 DB에 1 백만 명이 넘는 사용자가 있다는 것입니다.레일스에서 ​​DB 성능에 영향을주지 않으면 서 단시간에 1 백만 명의 사용자가있는 테이블에 사용자를위한 슬러그를 생성합니까?

다양한 방법을 설명하는 여러 블로그를 보았지만 제작 DB에서 위험을 감수하고 싶지 않습니다.이

  1. 아래의 방법은 이동 파일 자체에 슬러그를 생성 에 코드를 추가 제안 : 내가 찾은

    방법. 나는 레이크 작업에 의해 실행되는이 방법을 쓴

    class AddStatusToUser < ActiveRecord::Migration 
        class User < ActiveRecord::Base 
        end 
    
        def up 
        add_column :users, :status, :string 
        User.find_each do |user| 
         user.status = 'active' 
         user.save! 
        end 
        end 
    
        def down 
        remove_column :users, :status 
        end 
    end 
    
  2. : 아래 하나의 문제는 400 000 슬러그 지금까지 생성 된있는 사일 실행 된 것입니다. 나는 그것을 빨리하고 싶었지만 어떻게해야할지 모른다.

find_in_batches

:

는 배열로 찾기 옵션에 의해 발견 된 기록의 각 배치를 얻을 수 있습니다. 각 배치의 크기는 : batch_size 옵션으로 설정됩니다. 기본값은 1000입니다.

: start 옵션을 제공하여 일괄 처리의 시작점을 제어 할 수 있습니다. 이는 동일한 처리 대기열을 다루는 여러 작업자가 을 원할 때 특히 유용합니다. 작업자 1이 id 0과 10,000 사이의 모든 레코드를 처리하도록하고 작업자 2 을 10,000 이상에서 처리하도록 할 수 있습니다 (해당 작업자의 : start 옵션 설정).

주문을 설정할 수 없습니다. 이는 기본 키 ("id ASC")에서 오름차순으로 자동 설정되어 배치 순서 이 작동하게합니다. 즉,이 방법은 정수 기반 기본 키에서만 작동합니다. 제한을 설정할 수 없으므로 배치 크기를 제어하는 ​​데 사용됩니다.

DB 성능 문제를 피하기 위해 1000 명의 사용자가 모든 슬러그 생성 후 2 초의 절전 시간을 제공했습니다. 수면 방법을 제거해야합니까? 방금 User.find_each(&:save) 또는 방법 1을 실행해야합니까?

task :add_slug_to_all_users => :environment do 
    i=0 
    batchSize = 1000 
    puts "started at :#{Time.now}" 
    # find_in_batches method provides the users in batches of 1000 
    # so that the update is not triggered for all the rows at once which may lock the table completely. 
    User.where("slug is null and email is not null").find_in_batches(batch_size: batchSize) do |users| 
    sleep(2) 
    users.each {|u| u.save!; i+=1;} 
    puts "updated #{i} records at: #{Time.now}" 
    end 
    puts "Completed the Task at: #{Time.now}\n" 
end 

업데이트 1 : 나는 굼벵이를 생성하는 friendly_id 보석을 사용하고 있습니다.

업데이트 2는 : 나는 SHOW CREATE TABLE users를 실행하고 나는이있어 :

CREATE TABLE `users` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `first_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `last_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `p_views` int(11) DEFAULT '0', 
    `p_desc` text COLLATE utf8_unicode_ci, 
    `p_title` text COLLATE utf8_unicode_ci, 
    `created_at` datetime DEFAULT NULL, 
    `updated_at` datetime DEFAULT NULL, 
    `t_zone` varchar(255) COLLATE utf8_unicode_ci DEFAULT 'UTC', 
    `college` varchar(500) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `degree` text COLLATE utf8_unicode_ci, 
    `p_no` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL, 
    `slug` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `unique_phone_number` (`p_no`), 
    UNIQUE KEY `index_users_on_phone_no` (`p_no`), 
    UNIQUE KEY `index_users_on_slug` (`slug`), 
    KEY `use_index_on_college` (`college`(255)) 
) ENGINE=InnoDB AUTO_INCREMENT=2194 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci | 

내가 위의 결과에서 대부분의 필드를 제거했는지 유의하시기 바랍니다.slug 열은 first_namelast_name의 조합을 URL에 친숙한 방식으로 저장합니다.

예 : 사용자의 이름 인 경우 다음과 같을 것이다 생성

id first_name last_name 
1 Arun   Kumar 
2 Arun   Kumar 

슬러그 :

id slug 
1 arun-kumar 
2 arun-kumar1 
+0

제목과 질문을 수정해야하며 lakh (= 100,000)은 인도 국외에서 사용되지 않습니다. –

+0

@MichaelKohl 덕분에 1 백만 달러로 변경했습니다. – sahil

+0

슬러그가 어떻게 생성됩니까? 단일 쿼리에서 사용자 배치를 업데이트하는 것이 더 좋을 것이라고 생각합니다. – unkmas

답변

2

이 같은 상황에서 모든 용도의 제 3 자 소프트웨어는 방법으로 얻을 수 있습니다. SQL을 사용하여 작업을 수행하는 것이 좋습니다.

"슬러그"가 간단한 시퀀스 번호 인 경우 AUTO_INCREMENT을 추가하는 것이 확실한 해결 방법이며 영구적 인 솔루션입니다. 즉, 향후 모든 추가 작업으로 인해 슬러그가 자동으로 생성됩니다. 그 하나 문을 수행 할 수 있습니다 : slug 될 수 있도록

ALTER TABLE t 
    ADD COLUMN slug INT UNSIGNED AUTO_INCREMENT, 
    INDEX(slug); 

그것은 아마도 더 좋을 것 PRIMARY KEY (. SHOW CREATE TABLE를 제공하시기 바랍니다)하지만 그건 아마 테이블에 심각한 잠금을 필요로; 평범한 지수가 더 좋습니다. 그것을 테스트하십시오. 그것은 "충분히 빠르다"일지도 모른다.

다음 생각은 pt-online-schema-change입니다 (Percona.com 참조). 이는 효과가 거의 영향이없는 ALTERs을 효과적으로 수행하기위한 특수 도구입니다. 쓰기를 캡처하고 복사를 청크에 넣으려면 TRIGGER을 추가해야합니다. 약간의 영향은 "마지막 조금"으로 복사해야합니다. 최종 RENAME TABLE real TO old, new TO real;은 원자 적이며 본질적으로 순간적입니다. 심지어 "수면"을 동적으로 조정합니다. 수년간의 경험을 바탕으로 한 훌륭한 도구입니다.

그러나 ptosc는 PRIMARY KEY만큼 중요한 항목을 추가 할 수 없으므로 위 제안 (위)은 INDEX입니다.

한 번에 하나의 청크로 값을 설정하면 (을 통해) 올바른 방법입니다. 나는 chunking tips에 글을 썼다. DELETE을 목표로했지만 UPDATE에 맞출 수 있습니다.

find_in_batches()에서 "덮개 아래"가 무엇인지 알지 못해서 나는 그것이 좋든 나쁘다고 말할 수는 없습니다. 나는 OFFSET가 거의 항상 나쁘다는 것을 압니다. "중단 한 부분을 기억하는 것"이 ​​일반적으로 훨씬 좋습니다. 그러나 이미 UNIQUE 또는 PRIMARY 키가없는 경우 그렇게하기가 어렵습니다. PRIMARY은 클러스터링 때문에 더 좋습니다. (SHOW CREATE TABLE을 제공하십시오. 따라서 추측 할 필요가 없습니다.)

샘플 코드가 매번 테이블 시작 부분에서 시작되면 OFFSET을 사용하는 것만 큼 나쁘다 - 각 반복이 느려질 것입니다 이전 행보다 더 많은 행을 건너 뜁니다.

열을 추가 한 후 테이블에 대한 모든 참조를 확인하십시오. SELECT *에 이제 하나의 열이 추가됩니다 (*을 사용하지 않은 한 가지 이유). UPDATEsINSERTs은 누락 된 열과 함께 작동하지만 확인해야합니다.slug 열을 추가하고, 그것을 채우는 -

업데이트

두 단계가 있었다. 당신은 첫 번째 단계를 완료했습니다.

두 번째 단계를 수행하려면 AUTO_INCREMENT PRIMARY KEY을 사용하여 한 번에 100 개의 행을 스테핑하는 것이 좋습니다. 100은 너무 낮아 침습적이지 않습니다. AI PK는 전체 테이블을 포함하며 느린 OFFSET이나 느슨한 슬러그 세트를 검색 할 필요가 없도록 효율적입니다. 효율적인 청킹 here에 대해 논의합니다. DELETE으로 작성되었지만 기술은 UPDATE에 적용됩니다.

+0

감사합니다. Rick, 제 질문을 SHOW CREATE TABLE으로 업데이트했습니다. – sahil

+0

내 쿼리에서 오프셋을 사용하고 있지 않습니다. (블로그에서 읽는대로 정상적인 'limit'연산자보다 시간이 오래 걸립니다. mysql에서 사용됨) 슬래그가 생성되지 않은 사용자 만 선택할 수있는 조건을 지정했습니다. – sahil

+1

그러나 더 많은 슬래 이브 행을 건너 뛰려면 시간이 필요합니다. [_More_] (http : // mysql. rjweb.org/doc.php/pagination) 여기서 중단 한 부분을 기억하십시오. –