Mysql
 sql >> Database >  >> RDS >> Mysql

MySQL Mix illegale di regole di confronto

È utile comprendere le seguenti definizioni:

  • Una codifica dei caratteri dettagli come ogni simbolo è rappresentato in binario (e quindi memorizzato nel computer). Ad esempio, il simbolo é (U+00E9, minuscola latina E con acuto) è codificato come 0xc3a9 in UTF-8 (che MySQL chiama utf8 ) e 0xe9 in Windows-1252 (che MySQL chiama latin1 ).

  • Un insieme di caratteri è l'alfabeto dei simboli che possono essere rappresentati utilizzando una determinata codifica dei caratteri. In modo confuso, il termine è anche usato per indicare la stessa codifica dei caratteri.

  • Una collazione è un ordinamento su un set di caratteri, in modo che le stringhe possano essere confrontate. Ad esempio:latin1_swedish_ci di MySQL collation tratta la maggior parte delle variazioni accentate di un carattere come equivalenti al carattere di base, mentre il suo latin1_general_ci collation li ordinerà prima del carattere di base successivo ma non equivalenti (ci sono anche altre differenze più significative:come l'ordine di caratteri come å , ä , ö e ß ).

MySQL deciderà quale confronto applicare a una determinata espressione, come documentato in Fascicolazione di espressioni :in particolare, la collation di una colonna ha la precedenza su quella di una stringa letterale.

Il WHERE clausola della tua query confronta le seguenti stringhe:

  1. un valore in fos_user.username , codificato nel set di caratteri della colonna (Windows-1252) ed esprimendo una preferenza per le regole di confronto latin1_swedish_ci (con valore di coercibilità 2); con

  2. la stringa letterale 'Nrv⧧Kasi' , codificato nel set di caratteri della connessione (UTF-8, come configurato da Doctrine) ed esprimendo una preferenza per le regole di confronto della connessione utf8_general_ci (con un valore di coercibilità di 4).

Poiché la prima di queste stringhe ha un valore di coercibilità inferiore rispetto alla seconda, MySQL tenta di eseguire il confronto utilizzando le regole di confronto di quella stringa:latin1_swedish_ci . Per farlo, MySQL tenta di convertire la seconda stringa in latin1 —ma dal carattere non esiste in quel set di caratteri, il confronto non riesce.

Avviso

Ci si dovrebbe fermare un momento per considerare come è attualmente codificata la colonna:stai tentando di filtrare i record in cui fos_user.username è uguale a una stringa che contiene un carattere che non può esistono in quella colonna !

Se ritieni che la colonna fa contengono tali caratteri, quindi probabilmente hai scritto nella colonna mentre la codifica dei caratteri di connessione era impostata su qualcosa (ad es. latin1 ) che ha indotto MySQL a interpretare la sequenza di byte ricevuta come caratteri che sono tutti nel set di caratteri di Windows-1252.

Se questo è il caso, prima di continuare dovresti correggere i tuoi dati!

  1. convertire tali colonne nella codifica dei caratteri utilizzata per l'inserimento dei dati, se diversa dalla codifica incumbent:

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
    
  2. elimina le informazioni di codifica associate a tali colonne convertendole nel binary set di caratteri:

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
    
  3. associare a tali colonne la codifica in cui i dati sono stati effettivamente trasmessi convertendoli nel relativo set di caratteri.

    ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET bar;
    

Si noti che, se si esegue la conversione da una codifica multi-byte, potrebbe essere necessario aumentare la dimensione della colonna (o addirittura cambiarne il tipo) per accogliere la lunghezza massima possibile della stringa convertita.

Una volta che si è certi che le colonne siano codificate correttamente, è possibile forzare l'esecuzione del confronto utilizzando un confronto Unicode in uno dei due modi:

  • convertendo esplicitamente il valore fos_user.username in un set di caratteri Unicode:

    WHERE CONVERT(fos_user.username USING utf8) = ?
    
  • forzare la stringa letterale ad avere un valore di coercibilità inferiore rispetto alla colonna (causa una conversione implicita del valore della colonna in UTF-8):

    WHERE fos_user.username = ? COLLATE utf8_general_ci
    

Oppure si potrebbe, come dici tu, convertire permanentemente le colonne in una codifica Unicode e impostarne le regole di confronto in modo appropriato.

La considerazione principale è che le codifiche Unicode occupano più spazio rispetto ai set di caratteri a byte singolo, quindi:

  • potrebbe essere necessario più spazio di archiviazione;

  • i confronti possono essere più lenti; e

  • potrebbe essere necessario regolare la lunghezza del prefisso dell'indice (nota che il massimo è in byte, quindi potrebbe rappresentare un numero di caratteri inferiore rispetto a prima).

Inoltre, tieni presente che, come documentato in ALTER TABLE Sintassi :