Program Tip

“SET NAMES”사용 여부

programtip 2020. 12. 5. 10:31
반응형

“SET NAMES”사용 여부


O'Reilly의 "고성능 MySQL"을 읽다가 다음과 같은 것을 발견했습니다.

또 다른 일반적인 가비지 쿼리는 SET NAMES UTF8로, 어쨌든 작업을 수행하는 잘못된 방법입니다 (클라이언트 라이브러리의 문자 집합을 변경하지 않고 서버에만 영향을 미침).

나는 모든 스크립트의 맨 위에 "SET NAMES utf8"을 넣어서 db에 내 쿼리가 utf8로 인코딩되었음을 알 렸기 때문에 약간 혼란 스러웠습니다.

누구든지 위의 인용문에 대해 언급 할 수 있습니까? 또는 좀 더 공식적으로 말하자면, 내 데이터베이스 워크 플로가 유니 코드를 인식하도록하기위한 제안 / 모범 사례는 무엇입니까?

내 대상 언어는 관련이 있다면 php와 python입니다.


mysql_set_charset()옵션이 될 수 있지만 옵션은 ext/mysql. 들어 ext/mysqli그것이 mysqli_set_charset및 위해 당신은 연결 매개 변수를 지정해야합니다.PDO::mysql

이 함수를 사용하면 MySQL API 호출이 발생하므로 쿼리를 실행하는 것보다 훨씬 빠릅니다.

성능 측면에서 스크립트와 MySQL 서버 간의 UTF-8 기반 통신을 보장하는 가장 빠른 방법은 MySQL 서버를 올바르게 설정하는 것입니다. 다음 SET NAMES x같습니다 .

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

SET character_set_connection = x내부적으로도 실행 되지만 .NET Framework에서 이러한 서버 변수를 정적으로 SET collation_connection = <<default_collation_of_character_set_x>>설정할 수도 있습니다 .my.ini/cnf

동일한 MySQL 서버 인스턴스에서 실행되고 다른 문자 집합이 필요한 다른 응용 프로그램에서 발생할 수있는 문제에 유의하십시오.


TLDR

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

이 답변은 매우 유비쿼터스이기 때문에 php의 pdo 라이브러리에 중점을 둡니다.

간단한 알림-mysql은 클라이언트-서버 아키텍처입니다. 이는 실제 데이터베이스가있는 mysql 서버뿐만 아니라 mysql 서버와 통신하는 별도의 mysql 클라이언트 드라이버도 있기 때문에 중요합니다 (개별 엔티티입니다). mysql 클라이언트와 pdo가 함께 혼합되어 있다고 말할 수 있습니다.

를 사용할 때 set names utf8mysql에 표준 SQL 쿼리를 실행합니다. SQL 쿼리가 pdo를 통과 한 다음 mysql 클라이언트 라이브러리를 통과 한 다음 마지막으로 mysql 서버에 도달하는 동안 mysql 서버 만 해당 SQL 쿼리를 구문 분석하고 해석합니다. 이는 mysql 서버가 pdo 또는 mysql 클라이언트에게 문자 집합과 인코딩이 변경되었음을 알리는 메시지를 다시 보내지 않기 때문에 중요하며, 따라서 mysql 클라이언트와 pdo는 모두 발생 사실을 완전히 무지합니다.

클라이언트 라이브러리가 현재 문자 집합을 인식하지 못하는 경우 문자열을 제대로 처리 할 수 ​​없기 때문에이를 수행하지 않는 것이 중요합니다. 대부분의 일반적인 작업은 클라이언트가 올바른 문자 집합을 알지 못하더라도 올바르게 작동하지만 PDO :: quote 와 같은 문자열 이스케이프는 그렇지 않습니다 . 준비된 문을 사용하기 때문에 이러한 수동 기본 문자열 이스케이프에 대해 걱정할 필요가 없다고 생각할 수 있지만 pdo : mysql 의 기본 설정이었던 pdo : mysql 사용자의 대부분은 무의식적으로 에뮬레이트 된 준비된 문을 사용 합니다. 아주 오랜 시간 동안 운전사. 에뮬레이트 된 준비된 문은 mysql api에서 제공하는 실제 네이티브 mysql 준비된 문을 사용하지 않습니다. 대신 PHP는 다음을 호출하는 것과 동일합니다.PDO::quote() 모든 값에 대해 따옴표로 묶은 값으로 모든 자리 표시자를 str_replacing합니다.

사용중인 문자 집합을 알지 않으면 문자열을 제대로 이스케이프 할 수 없기 때문에 에뮬레이트 된 준비된 문은를 통해 특정 문자 집합으로 변경 한 경우 SQL 주입에 취약합니다 set names. SQL 삽입 가능성에 관계없이 다른 문자 집합을위한 이스케이프 체계를 사용하면 문자열을 끊을 수 있습니다.

pdo mysql 드라이버의 경우, DSN에서 지정하여 연결할 때 문자 집합을 지정할 수 있습니다 . 이렇게하면 클라이언트 라이브러리와 서버가 둘 다 문자 집합을 인식하므로 정상적으로 작동합니다.

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

그러나 부적절한 문자열 이스케이프가 유일한 문제는 아닙니다. 예를 들어, 열 이름이 문자열로 지정되어 인코딩이 중요하기 때문에 PDO :: bindColumn 사용에 문제가있을 수도 있습니다 . 예라는 이름의 열 이름이 될 수 ütube(움라우트주의), 당신은 전환 latinutf8설정 이름을 통해, 그리고 당신은 시도 $stmt->bindColumn('ütube', $var);와 함께 ütube당신의 PHP 파일이 UTF8 인코딩되기 때문에 UTF8 인코딩 된 문자열 인. 작동하지 않습니다. 문자열을 latin1 변형으로 인코딩해야합니다. 이제 모든 종류의 미친 짓이 진행됩니다.


py에 대해서는 확실하지 않지만 php는 mysql_set_charset현재 "문자셋을 변경하는 선호하는 방법이고] mysql_query ()를 사용하여 SET NAMES를 실행하는 것은 권장되지 않는다고 말합니다. 이 함수는 MySQL 5.0.7 용으로 도입되었으므로 이전 버전에서는 작동하지 않습니다.

mysql_set_charset('utf8', $link);

$ link는 다음으로 생성 된 연결입니다. mysql_connect

참고 URL : https://stackoverflow.com/questions/1650591/whether-to-use-set-names

반응형