È folle aggirare i problemi di distinzione tra maiuscole e minuscole del database memorizzando maiuscole e minuscole originali?

StackOverflow https://stackoverflow.com/questions/4016674

  •  26-09-2019
  •  | 
  •  

Domanda

Sto implementando un database in cui diverse tabelle hanno dati stringa come chiavi candidate (ad esempio:nome utente) e verranno indicizzati di conseguenza.Per questi campi voglio:

  1. Insensibilità alle maiuscole e minuscole quando qualcuno interroga la tabella su quelle chiavi

  2. Il caso scritto inizialmente deve essere conservato in qualche modo in modo che l'applicazione possa presentare i dati all'utente con il caso originale utilizzato

Voglio anche che lo schema del database sia il più indipendente possibile dal database, poiché il codice dell'applicazione non è (o non dovrebbe essere) asservito a un particolare RDBMS.

Vale anche la pena notare che la stragrande maggioranza delle query eseguite sul database verrà eseguita dal codice dell'applicazione, non tramite l'accesso diretto alla tabella da parte del client.

Nell'implementare questo, sto riscontrando molti problemi fastidiosi.Uno è che non tutti gli RDBMS implementano COLLATE (che è il punto in cui la sensibilità ai casi sembra essere regolabile a livello di schema) allo stesso modo.Un altro problema è che le opzioni di confronto e distinzione tra maiuscole e minuscole possono essere impostate su più livelli (server, database, tabella (?), colonna) e non posso garantire all'applicazione quale impostazione otterrà.Ancora un altro problema è che COLLATE stesso può diventare complicato perché c'è molto di più oltre alla semplice distinzione tra maiuscole e minuscole (ad esempio:opzioni Unicode).

Per evitare tutti questi grattacapi, quello che sto considerando è evitare del tutto il problema memorizzando due colonne per un dato.Una colonna con il caso originale, un'altra ridotta in minuscolo dal livello dell'applicazione.

per esempio:Due dei campi nella tabella

user_name = "fredflintstone" (a unique index on this one)
orig_name = "FredFlintstone" (just data... no constraints)

I pro e i contro di questo per come la vedo io sono:

Professionisti:

  1. Nessuna ambiguità: il codice dell'applicazione gestirà le conversioni dei casi e non dovrò mai preoccuparmi che i test unitari falliscano "misteriosamente" quando cambiano le impostazioni/RDBMS sottostanti.

  2. Le ricerche sull'indice saranno pulite e non saranno mai rallentate dalle funzionalità di confronto o dalle chiamate a LOWER() o altro (supponendo che tali cose rallentino l'indice, il che sembra logico)

Contro:

  1. Spazio di archiviazione aggiuntivo richiesto per i dati raddoppiati

  2. Sembra un po' brutale

So che funzionerà, ma allo stesso tempo ha un odore sbagliato.

È folle/inutile farlo?C'è qualcosa che non so che rende il problema della distinzione tra maiuscole e minuscole meno complicato di quanto mi sembri in questo momento?

È stato utile?

Soluzione

Ho visto spesso i dati duplicati in questo modo per motivi di prestazioni.Ti permette di conservare l'involucro originale (che ovviamente ti servirà perché non sempre riesci a indovinare quale dovrebbe essere l'involucro, non puoi essere sicuro che ogni nome inizi con una lettera maiuscola, ad esempio).Se il database non supporta altri modi per farlo (indici funzionali), allora questo è pratico, non folle.È possibile mantenere i dati coerenti utilizzando i trigger.

Altri suggerimenti

Naturalmente, decisioni come questa sono sempre un compromesso, ma non penso che si tratti necessariamente di "dati raddoppiati".Minuscolare una stringa può essere un'operazione non banale, in particolare se si va oltre l'ASCII, quindi la versione minuscola della stringa non è semplicemente "duplicata".È in qualche modo correlato alla stringa originale, ma non di più.

Se lo consideri un analogo alla memorizzazione dei risultati calcolati nel DB, diventa più naturale.

La possibilità di interrogare su UPPER(UserName) è un'altra buona soluzione, che evita la seconda colonna.Tuttavia, per usarlo è necessario almeno un affidabile UPPER funzione (dove in particolare è possibile controllare le impostazioni locali utilizzate per i caratteri non ASCII) e probabilmente indici basati su funzioni per prestazioni decenti.

Le ricerche sull'indice saranno pulite e non saranno mai rallentate dalle funzionalità di confronto o dalle chiamate a LOWER() o altro (supponendo che tali cose rallentino l'indice, il che sembra logico)

No, non è logico.Puoi avere indici su funzioni costanti.

create index users_name on users(name); -- index on name
create index users_name_lower on users(lower(name)); -- index on the function result

Il tuo RDBMS dovrebbe essere abbastanza intelligente da sapere come usarlo users_name_lower quando riceve questa query:

select * from users where lower(name) = ?

Senza users_name_lower, sì, questo dovrebbe essere superato.Con l'indice funzionale, fa la cosa giusta.

Suggerisci alle tue query di ricerca di fare qualcosa del genere:

  • SELECT * FROM Users WHERE LOWER(UserName) = LOWER('fredFlinstone')
  • includere esplicitamente l'hint COLLATION nella query quando la distinzione tra maiuscole e minuscole deve essere ignorata/rispettata

Considererei troppo onerosa la duplicazione dei dati per la distinzione tra maiuscole e minuscole.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top