2012-03-08 13 views
9

Quiero agregar un índice a una base de datos de producción. Afortunadamente, estamos ejecutando Postgres, lo que permite una indexación simultánea, por lo que podemos agregar un índice sin tiempo de inactividad. Los índices concurrentes de captura no se pueden agregar desde una transacción, y las migraciones de rieles envuelven todo dentro de una transacción.¿Cómo detener la migración de Rails 3.1 para que no se ejecute en una transacción?

Afortunadamente, hay algo que parece una solución realmente simple: sobrescribir el método privado ddl_transaction de ActiveRecord :: Migration, como explained here.

class IndexUsersEmails < ActiveRecord::Migration 
    def ddl_transaction(&block) 
    block.call # do not start a transaction 
    end 

    def self.up 
    execute "CREATE INDEX CONCURRENTLY index_users_on_email ON users(email)" 
    end 
end 

El problema es que no parece funcionar en Rails 3.1. Hago exactamente lo que hace el código en Gist, y los rieles parecen ignorarlo por completo. ¿Alguna idea de dónde ir con esto?

+0

¿Ha intentado cambiar la definición del método de manera que se trata de un método de la clase? p.ej. 'def self.ddl_transaction (& block) ...' –

Respuesta

11

Acabo de darme cuenta de que nunca acepté una respuesta aquí, así que debería decir lo que hice. Resulta que se puede salir de la transacción como esta:

class AddFbPageIdIndexToTabs < ActiveRecord::Migration 
    def up 
    execute "END" 
    execute "CREATE INDEX CONCURRENTLY bob_lob_law_index ON bob_lob (law)" 
    execute "BEGIN" 
    end 

    def down 
    execute "END" 
    execute "DROP INDEX CONCURRENTLY bob_lob_law_index" 
    execute "BEGIN" 
    end 
end 

Sólo tiene que ejecutar un execute "END" antes de lo que desea ejecutar fuera de la transacción. Esto finalizará la transacción que ActiveRecord :: Migration configuró automágicamente para la migración. Una vez que haya terminado con el código que desea ejecutar fuera de la transacción, execute "BEGIN" abre una nueva transacción para que ActiveRecord :: Migration pueda pasar por su proceso de limpieza y cerrar la transacción que cree que se abrió.

(no recuerdo donde he encontrado en línea este truco, y no se puede encontrar ahora. Las modificaciones dan la bienvenida a la fuente de esto!)

1

No estoy diciendo que esta es la "manera correcta" de hacerlo, pero lo que funcionó para mí fue ejecutar solo esa migración de forma aislada.

rake db:migrate:up VERSION=20120801151807 

donde 20120801151807 es la marca de tiempo del CREATE migración de índices simultáneamente.

Aparentemente, no usa una transacción cuando ejecuta una sola migración.

Cuestiones relacionadas