Δευτέρα, 8 Οκτωβρίου 2012

MySQL και ελληνικά

Από ότι φαίνεται όταν λέμε στη MySQL utf8 και utf8_unicode_ci, αυτό δεν είναι αρκετό για να "κάνει το σωστό" σε όλες τις περιπτώσεις. Όλα ξεκινούν από αυτό:
> select 'λαχτάρα' = 'λαχταρά' collate utf8_general_ci;
1
> select 'λαχτάρα' = 'λαχταρά' collate utf8_unicode_ci;
1


Αυτό από τη μια μεριά είναι καλό σε ορισμένες περιπτώσεις όπου αναζητάς π.χ., για "κοροϊδεύω" και θέλεις η αναζήτηση να συμπεριλάβει και το "κοροιδευω" στα αποτελέσματα, αλλά έχει και μια απροσδόκητη σχετικά συνέπεια.

Ας υποθέσουμε ότι έχετε αποθηκεύσει τη φράση "Τι λες ρε φιλέ τωρά" σε ένα varchar πεδίο σε ένα πίνακα με InnoDB engine. Μετά την ξαναβλέπετε, παρατηρείτε ότι οι τόνοι είναι τελείως λάθος (ή σας το λέει αυτό ο ορθογραφικός έλεγχος), τους διορθώνετε και πάτε να αποθηκεύσετε τις αλλαγές. Η MySQL σας λέει χαρούμενη ότι τις αποθήκευσε κι εσείς κοιτάτε το αποτέλεσμα για να ανακαλύψετε έκπληκτοι ότι στην πραγματικότητα δεν άλλαξε τίποτα ...

Τι έχει συμβεί; Απλά η InnoDB κάνει μια σύγκριση του string που θέλετε να αποθηκεύσετε με τα τωρινά περιεχόμενα χρησιμοποιώντας το collation του πίνακα (πιθανότατα utf8_general_ci ή utf8_unicode_ci) πριν αποθηκεύσει. Η σύγκριση της λέει ότι δεν έχει γίνει κάποια αλλαγή με αποτέλεσμα η InnoDB να επιστρέφει "επιτυχία" και να παραλείπει να αλλάξει οτιδήποτε. Η InnoDB πάει μετά για ύπνο χαρούμενη ότι σας γλύτωσε από ένα τσάμπα disk access κι εσείς αναρωτιέστε τι έγιναν τα δεδομένα σας ...

Αντίστοιχο πρόβλημα παρουσιάζεται όταν έχετε ένα πίνακα στον οποίο μια ελληνική λέξη μπορεί να εμφανίζεται πάνω από μία φορές και θέλετε να μετρήσετε πόσες είναι συνολικά οι εμφανίσεις της υποθέτοντας ότι όλες οι καταχωρήσεις είναι σωστές ορθογραφικά (δηλ. έχουν τους τόνους τους και μάλιστα στη σωστή θέση). Σε αυτή την περίπτωση αν στα αποτελέσματα για "φίλε" συμπεριληφθεί και το "φιλέ" θα αναρωτιέστε τι στο καλό κάνει τα test σας να σκάνε στην περίπτωση των ελληνικών (φυσικά έχετε πολλά και καλά test έτσι δεν είναι;).

Η απάντηση σε όλες τις παραπάνω περιπτώσεις είναι η προσεκτική χρήση του utf8_bin collation:

> select 'λαχτάρα' = 'λαχταρά' collate utf8_bin;
0

Ακριβέστερα, αυτό που βολεύει συνήθως είναι η χρήση του utf8_bin για την αποθήκευση και η επιλεκτική χρήση του utf8_unicode_ci explicitly σε queries που έχουν "ORDER BY", ώστε να χρησιμοποιούνται οι κανόνες ταξινόμησης της ελληνικής γλώσσας.

Keep on hacking!

Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου