2009-10-30 30 views
53

Khi đọc "MySQL hiệu suất cao" từ O'Reilly Tôi đã stumbled khi truy vấnCho dù sử dụng "SET TÊN"

Một rác phổ biến sau đây được SET TÊN UTF8, đó là con đường sai để vẫn làm mọi thứ (nó không thay đổi bộ ký tự của thư viện khách hàng; nó chỉ ảnh hưởng đến máy chủ).

Tôi hơi bối rối, vì tôi đã từng đặt "SET NAMES utf8" ở đầu mỗi tập lệnh để cho db biết rằng truy vấn của tôi được mã hóa utf8.

Bất cứ ai có thể nhận xét báo giá trên, hoặc, để đưa nó chính thức hơn, đề xuất của bạn/thực tiễn tốt nhất để đảm bảo rằng quy trình làm việc cơ sở dữ liệu của tôi là unicode-aware.

Ngôn ngữ mục tiêu của tôi là php và python nếu điều này có liên quan.

+2

bạn đã thực hiện kỹ thuật nào? –

Trả lời

28

mysql_set_charset() sẽ là một lựa chọn - nhưng một tùy chọn giới hạn trong ext/mysql. Đối với ext/mysqli, nó là mysqli_set_charset và cho PDO::mysql bạn cần chỉ định thông số kết nối.

Khi sử dụng chức năng này dẫn đến một cuộc gọi API MySQL, nó sẽ được xem xét nhanh hơn nhiều so với phát hành truy vấn.

Về mặt hiệu suất, cách nhanh nhất để đảm bảo giao tiếp dựa trên UTF-8 giữa tập lệnh của bạn và máy chủ MySQL đang thiết lập máy chủ MySQL chính xác. Như SET NAMES xequivalent để

SET character_set_client = x; 
SET character_set_results = x; 
SET character_set_connection = x; 

trong khi SET character_set_connection = x nội bộ cũng thực hiện SET collation_connection = <<default_collation_of_character_set_x>> bạn cũng có thể thiết lập these server variables tĩnh trong my.ini/cnf của bạn.

Hãy lưu ý các vấn đề có thể xảy ra với các ứng dụng khác đang chạy trên cùng một cá thể máy chủ MySQL và yêu cầu một số bộ ký tự khác.

+3

Kể từ PHP 5.0.5, có một phương thức trong mysqli: http://php.net/mysqli_set_charset – xofer

+0

Tôi đã đề cập đến 'mysql_set_charset()' - đó là một hàm có trong 'ext/mysql' cũ. Như đã nói ở trên, cả 'PDO' lẫn 'ext/mysqli' đều không hỗ trợ trực tiếp cho hoạt động này. –

+1

Dường như liên kết tôi đăng không đáng tin cậy. Đây là một tốt hơn: http://php.net/manual/en/mysqli.set-charset.php Không chắc chắn làm thế nào bạn có nghĩa là mysqli không hỗ trợ hoạt động này. – xofer

9

Không chắc chắn về py, nhưng php có mysql_set_charset bây giờ, trong đó nói rằng "cách ưa thích để thay đổi bộ ký tự [và] bằng cách sử dụng mysql_query() để thực thi SET NAMES không được khuyến khích." Lưu ý rằng chức năng này đã được giới thiệu cho MySQL 5.0.7, vì vậy nó sẽ không hoạt động với các phiên bản trước đó.

mysql_set_charset('utf8', $link); 

đâu $ link là một kết nối được tạo ra với mysql_connect

21

TLDR

// The key is the "charset=utf8" part. 
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8'; 
$dbh = new PDO($dsn, 'user', 'pass'); 

Câu trả lời này có một sự nhấn mạnh về thư viện PDO php vì nó quá phổ biến.

Lời nhắc ngắn gọn - mysql là kiến ​​trúc máy khách-máy chủ. Điều này là quan trọng bởi vì không chỉ có máy chủ mysql nơi mà cơ sở dữ liệu thực tế là, nhưng cũng có trình điều khiển máy khách mysql riêng biệt, đó là điều mà nói chuyện với máy chủ mysql (chúng là các thực thể riêng biệt). Bạn có thể kinda sorta nói rằng khách hàng mysql và pdo được trộn lẫn với nhau.

Khi bạn sử dụng set names utf8, bạn phát hành truy vấn sql chuẩn vào mysql.Trong khi truy vấn sql đi qua pdo, và sau đó thông qua thư viện khách hàng mysql, và sau đó cuối cùng nó đạt đến máy chủ mysql, CHỈ máy chủ mysql phân tích cú pháp và giải thích truy vấn sql đó. Điều này là quan trọng bởi vì máy chủ mysql không gửi bất kỳ thư nào trở lại pdo hoặc máy khách mysql cho biết bộ ký tự và mã hóa đã thay đổi, và do đó, pdo hoàn toàn không biết thực tế là nó đã xảy ra.

Điều quan trọng là không làm điều này vì thư viện khách hàng không thể xử lý đúng chuỗi nếu nó không nhận thức được bộ ký tự hiện tại. Các hoạt động phổ biến nhất sẽ hoạt động chính xác mà không có máy khách biết bộ ký tự chính xác, nhưng một thao tác không phải là chuỗi thoát, chẳng hạn như PDO::quote. Bạn có thể nghĩ rằng bạn không cần phải lo lắng về việc thoát khỏi chuỗi nguyên thủy thủ công vì bạn sử dụng các câu lệnh chuẩn bị sẵn sàng, nhưng sự thật là đại đa số pdo: người dùng mysql vô tình sử dụng emulated prepared statements vì nó là thiết lập mặc định cho trình điều khiển pdo: mysql cho một thời gian rất dài. Một câu lệnh được mô phỏng đã được mô phỏng không sử dụng các câu lệnh chuẩn mysql có nguồn gốc thực như được cung cấp bởi api mysql; thay vào đó, php thực hiện tương đương với việc gọi PDO::quote() trên tất cả các giá trị của bạn và str_replacing'ing tất cả các trình giữ chỗ của bạn với các giá trị được trích dẫn cho bạn.

Vì bạn không thể thoát đúng chuỗi trừ khi bạn biết bộ ký tự bạn đang sử dụng, các câu lệnh được mô phỏng được mô phỏng này dễ bị chèn ép sql nếu bạn đã thay đổi thành bộ ký tự nhất định thông qua tên tập hợp. Bất kể khả năng tiêm sql, bạn vẫn có thể phá vỡ các chuỗi của bạn nếu bạn sử dụng một lược đồ thoát cho một bộ ký tự khác nhau.

Đối với trình điều khiển mysql pdo, bạn có thể chỉ định ký tự được đặt khi bạn kết nối, theo specifying it in the DSN. Thư viện máy khách và máy chủ sẽ nhận thức được bộ ký tự nếu bạn làm điều này.

// The key is the "charset=utf8" part. 
$dsn = 'mysql:host=localhost;dbname=testdb;charset=utf8'; 
$dbh = new PDO($dsn, 'user', 'pass'); 

Nhưng thoát chuỗi không đúng không phải là vấn đề duy nhất. Ví dụ: bạn cũng có thể gặp sự cố khi sử dụng PDO::bindColumn vì tên cột được chỉ định dưới dạng chuỗi và do đó mã hóa lại quan trọng. Ví dụ có thể là tên cột có tên là ütube (ghi chú âm sắc) và bạn chuyển từ latin thành utf8 thông qua tên bộ và sau đó bạn thử $stmt->bindColumn('ütube', $var); với ütube là chuỗi được mã hóa utf8 vì tệp php của bạn được mã hóa utf8. Nó sẽ không hoạt động, bạn sẽ cần phải mã hóa chuỗi như là một biến thể latin1 ... và bây giờ bạn có tất cả các loại điên xảy ra.

+2

Như ngày nay (tháng 9 năm 2014) PDO là cách mới nhất và mạnh mẽ nhất để kết nối PHP với cơ sở dữ liệu, tôi nghĩ câu trả lời này là câu trả lời nên được chấp nhận. – rogeriopradoj

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