PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Come creare un indice su LOWER(users.username) in Rails (usando postgres)

Sì, quella convalida farebbe quel tipo di query e quel tipo di query eseguirà una scansione della tabella.

In realtà hai un paio di problemi qui:

  • La validazione è soggetta a race condition perché la logica non è nel database a cui appartiene. Il database dovrebbe essere responsabile di tutti i problemi di integrità dei dati indipendentemente dalla consueta ideologia Rails.
  • La tua convalida attiva le scansioni delle tabelle e a nessuno piacciono le scansioni delle tabelle.

Puoi risolvere entrambi questi problemi con un indice. Il primo problema viene risolto utilizzando un indice univoco all'interno del database. Il secondo problema viene risolto indicizzando il risultato di lower(username) anziché username .

AFAIK Rails continua a non capire gli indici sulle espressioni, quindi dovrai fare due cose:

  1. Passa da schema.rb a structure.sql per impedire a Rails di dimenticare il tuo indice. Nel tuo config/application.rb vorrai impostare:

    config.active_record.schema_format = :sql
    

    Dovrai anche iniziare a usare il db:structure:* rake task invece di db:schema:* compiti. Dopo essere passato a structure.sql , puoi eliminare db/schema.rb poiché non verrà più aggiornato o utilizzato; vorrai anche iniziare a monitorare db/structure.sql nel controllo di revisione.

  2. Crea l'indice a mano scrivendo un po' di SQL in una migrazione. Questo è facile:

    def up
      connection.execute(%q{
        create index idx_users_lower_username on users(lower(username))
      })
    end
    
    def down
      connection.execute(%q{
        drop index idx_users_lower_username
      })
    end
    

Ovviamente questo ti lascerà con cose specifiche di PostgreSQL, ma non c'è nulla di cui preoccuparsi poiché ActiveRecord non ti offre comunque alcuna portabilità utile.