2012-01-02 23 views
9

Tôi có một bảng với một lĩnh vực một sử dụng mã hóa utf8 và collation utf8_unicode_ci:Trường hợp độc đáo nhạy cảm và phân biệt dạng chữ tìm kiếm

CREATE TABLE dictionary (
    a varchar(128) NOT NULL 
) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

Các utf8_unicode_ci chiếu là cần thiết cho một hiệu quả case insensitive tìm kiếm với phần mở rộng và thắt ống. Với mục đích này tôi có chỉ số:

CREATE INDEX a_idx on dictionary(a); 

Vấn đề: Ngoài ra tôi phải đảm bảo rằng tất cả các giá trị được lưu trữ trong những lĩnh vực một là duy nhất nhưng trong một trường hợp nhạy cảm cách. Ví dụ của Đức: "blühen" và "Blühen" cả hai đều phải được lưu trữ trong bảng. Nhưng thêm "Blühen" lần thứ hai là không thể.

Có chức năng tích hợp trong MySQL để có cả hai không?

Rất tiếc, có vẻ như không thể đặt collation cho chỉ mục trong MySQL 5.1.

Các giải pháp cho vấn đề này bao gồm kiểm tra tính duy nhất trước khi chèn hoặc kích hoạt. Cả hai đều kém thanh lịch hơn so với sử dụng một chỉ mục duy nhất.

+0

Thật không may, MySQL thiếu các tính năng như chỉ số/lượt xem vật hoá hoặc cột được tính toán hoặc chỉ mục dựa trên chức năng mà RDBMS khác có. Tôi muốn được quan tâm để xem làm thế nào nó được thực hiện tất nhiên ... – gbn

+0

Sẽ thêm một cột với một trường hợp nhạy cảm collation và uniquness ràng buộc làm việc cho bạn? –

+0

Tôi nghĩ rằng chủ đề này là một trợ giúp tốt. http://stackoverflow.com/questions/4945349/mysql-search-with-uft8-general-ci-is-case-sensitive-for-fulltext – MahanGM

Trả lời

4

Vâng, có 2 cách để thực hiện điều này:

  1. sử dụng _bin chiếu
  2. thay đổi kiểu dữ liệu của bạn để VARBINARY

Trường hợp 1: sử dụng _bin chiếu

Tạo bảng của bạn như sau:

CREATE TABLE `dictionary` (
`a` VARCHAR(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, 
UNIQUE KEY `idx_un_a` (`a`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

Xin lưu ý:

  1. datatype của cột a
  2. chỉ số UNIQUE trên cột a

Trường hợp 2: sử dụng VARBINARY dataype

Tạo bảng của bạn như sau:

CREATE TABLE `dictionary` (
`a` VARBINARY(128) NOT NULL, 
UNIQUE KEY `idx_uniq_a` (`a`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 

Xin lưu ý:

  1. kiểu mới VARBINARY
  2. chỉ số UNIQUE trên cột a

Vì vậy, cả hai bên trên sẽ giải quyết mục đích của bạn. Tức là, cả hai sẽ cho phép các giá trị như 'abc', 'Abc', 'ABC', 'aBc' vv nhưng không cho phép cùng một giá trị nếu trường hợp khớp nhau.

Xin lưu ý rằng việc đối chiếu "_bin" khác với việc sử dụng kiểu dữ liệu nhị phân.Vì vậy, xin vui lòng tham khảo các liên kết sau đây:

  1. The BINARY and VARBINARY datatypes
  2. The _bin and binary Collations

Tôi hy vọng ở trên sẽ giúp!

+0

Cảm ơn bạn đã trả lời! Tôi không thể thấy làm thế nào với giải pháp này sẽ có hiệu quả (O (log (n)) và tìm kiếm phân biệt chữ hoa chữ thường – user1091141

+0

@ user1091141, ofcourse bạn có thể thực hiện tìm kiếm phân biệt chữ hoa chữ thường bằng cách thay đổi collation, ví dụ truy vấn như 'SELECT * FROM dictionary WHERE a COLLATE utf8_general_ci = 'abc''. Xin lỗi nếu câu trả lời của tôi không rõ ràng về nó nhưng tôi đoán bạn có thể tìm ra, đây là một liên kết - "http://dev.mysql.com/doc/refman/5.0 /en/case-sensitivity.html ". Về O (log (n)), tôi xin lỗi nhưng toán học của tôi không phải là mạnh mẽ, nhưng tôi không thấy tại sao tìm kiếm sẽ không hiệu quả. Hoặc bạn có thể giữ 2' a 'cột - một cột với collation chung cho tìm kiếm phân biệt chữ hoa chữ thường và _bin với trường hợp nhạy cảm chữ hoa chữ thường – Abhay

+2

nếu tôi chỉ định một đối chiếu khác nhau trong mệnh đề where so với định nghĩa trong định nghĩa bảng, MySQL sẽ không sử dụng chỉ mục nhưng Quét toàn bộ bảng có thể mất một thời gian dài cho các bảng lớn, đó là lý do tại sao chúng có thể được kiểm tra suy luận là không hiệu quả. Thực hiện lệnh SELECT EXPLAIN SELECT * FROM WHERE a COLLATE utf8_general_ci = 'abc'' cho thấy tất cả các hàng trong bảng được đọc. Điều này ít nhất là cho phiên bản MySQL của tôi (5.0 và 5.1). Sẽ tốt nếu nó sẽ khác. – user1091141

1

Bạn có thể đạt được điều này bằng cách thêm cột bổ sung 'column_lower'.

CREATE TABLE `dictionary` (
    `a` VARCHAR(128) NOT NULL, 
    `a_lower` VARCHAR(128) NOT NULL, 
    UNIQUE KEY `idx_un_a_lower` (`a_lower`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 

Insert mà đi như thế này:

insert into dictionary set a = x, a_lower = lower(x); 

Chọn bây giờ có thể được case-insensitive:

select * from dictionary where a_lower like lower('search_term%') 

Lưu ý rằng cột trong đó có chỉ số trên đó, có thể lưu trữ tại tối đa 191 ký tự . MySQL có thể có tối đa 767 byte dài chỉ mục, đó là 767/4 (unicode có thể mất đến 4 byte nếu bạn sử dụng utf8mb4 collation) = 191,75 = 191 ký tự. Nếu bạn sử dụng đối chiếu utf8 chiếm tối đa 3 byte cho mỗi cột ký tự có thể lưu trữ ở mức tối đa 767/3 = 255 ký tự.

0
SELECT * FROM dictionary WHERE a COLLATE utf8_general_ci = 'abc' 

Hãy thử tính năng này sẽ hoạt động .. nó hiệu quả với tôi.

Các vấn đề liên quan