PostgreSQL 데이터베이스에서 LC_CTYPE의 영향은 무엇입니까?


25

그래서 PostgreSQL이 설치된 데비안 서버가 거의 없습니다. 역사적으로 이러한 서버와 PostgreSQL은 라틴 9 문자 세트로 현지화되어 그 당시에는 괜찮 았습니다. 이제 우리는 폴란드어, 그리스어 또는 중국어와 같은 것을 처리해야하므로 변경이 점점 커지고 있습니다.

UTF8 데이터베이스를 만들려고 할 때 메시지가 나타납니다.

오류 : UTF8 인코딩이 로케일 fr_FR과 일치하지 않습니다. 세부 사항 : 선택한 LC_CTYPE 설정에는 인코딩 LATIN9가 필요합니다.

몇 번이나 내 오래된 친구 Google로 주제에 대해 조사한 결과, 데비안 업데이트 LANG, PostgreSQL을 올바른 문자 세트로 다시 컴파일, 모든 LC_시스템 변수 및 기타 모호한 솔루션 편집과 같은 지나치게 복잡한 절차 만 발견 할 수있었습니다 . 당분간은이 문제를 제쳐 두었습니다.

최근에 다시 돌아 왔는데, 그리스인들은 물건을 원하고 라틴 9는 원하지 않습니다. 그리고이 문제를 다시 살펴 보는 동안 한 동료가 내게 와서“아, 쉽게 봅니다.”라고 말했습니다.

그는 아무것도 편집하지 않았고, 마술을하지 않았으며, 단지이 SQL 쿼리를 만듭니다.

CREATE DATABASE my_utf8_db
  WITH ENCODING='UTF8'
       OWNER=admin
       TEMPLATE=template0
       LC_COLLATE='C'
       LC_CTYPE='C'
       CONNECTION LIMIT=-1
       TABLESPACE=pg_default;

그리고 잘 작동했습니다.

나는 실제로 알지 못했고 LC_CTYPE='C'이것을 사용하는 것이 Google의 첫 번째 솔루션이 아니고 심지어 스택 오버플로가 아니라는 것에 놀랐습니다. 나는 둘러보고 PostgreSQL 문서에 대한 언급 만 발견했습니다.

LC_CTYPE이 C 또는 POSIX 인 경우 모든 문자 세트가 허용되지만 LC_CTYPE의 다른 설정의 경우 올바르게 작동하는 문자 세트가 하나만 있습니다. LC_CTYPE 설정은 initdb에 의해 고정되므로 C 또는 POSIX 로케일을 선택할 때를 제외하고 클러스터의 서로 다른 데이터베이스에서 다른 인코딩을 사용하는 명백한 유연성은 실제보다 더 이론적입니다 (따라서 실제 로케일 인식을 사용 안함).

그래서, 이것이 너무 쉽고 완벽하다는 것이 궁금했습니다. 단점은 무엇입니까? 그리고 나는 아직 답을 찾는 데 어려움을 겪었습니다. 그래서 여기에 게시하겠습니다.

tl; dr : 특정 지역화에 비해 단점은 무엇입니까 LC_CTYPE='C'? 그렇게하는 것이 나쁜가요? 무엇을 깨뜨릴 수 있을까요?

답변:


25

특정 지역화에서 LC_CTYPE = 'C'사용의 단점은 무엇입니까

이 문서는 로케일 지원 에서 로케일과 SQL 기능 사이의 관계를 언급합니다 .

로케일 설정은 다음 SQL 기능에 영향을줍니다.

  • ORDER BY 또는 텍스트 데이터에 대한 표준 비교 연산자를 사용하여 쿼리에서 정렬 순서

  • 상한, 하한 및 initcap 함수

  • 패턴 일치 연산자 (LIKE, SIMILAR TO 및 POSIX 스타일 정규식); 로케일은 대소 문자를 구분하지 않는 일치와 문자 클래스 정규 표현식으로 문자 분류에 영향을줍니다.

  • to_char 함수 군

  • LIKE 절과 함께 인덱스를 사용하는 기능

첫 번째 항목 (정렬 순서)은 LC_COLLATE약하고 다른 항목은 모두 약 것 같습니다 LC_CTYPE.

LC_COLLATE

LC_COLLATE문자열 간의 비교에 영향을줍니다. 실제로 가장 눈에 띄는 효과는 정렬 순서입니다. LC_COLLATE='C'(또는 POSIX동의어)는 비교를 유발하는 바이트 순서임을 language_REGION의미하지만 형식 의 로캘은 문화적 규칙이 비교를 주도한다는 것을 의미합니다.

UTF-8 데이터베이스 내부에서 실행되는 프랑스어 이름의 예 :

select firstname from (values ('bernard'), ('bérénice'), ('béatrice'), ('boris'))
 AS l(firstname)
order by firstname collate "fr_FR";

결과:

 이름 
-----------
 베아트리체
 베레 니체
 남자 이름
 보리스

béatrice전에 제공 boris이 있다면 비 악센트로 악센트 E는 O에 대해 비교 때문이다. 문화적 규칙입니다.

이것은 C로케일 에서 발생하는 것과 다릅니다 .

select firstname from (values ('bernard'), ('bérénice'), ('béatrice'), ('boris')) 
 AS l(firstname)
order by firstname collate "C";

결과:

 이름 
-----------
 남자 이름
 보리스
 베아트리체
 베레 니체

이제 악센트 E가있는 이름이 목록의 끝에서 푸시됩니다. éUTF-8 의 바이트 표현은 16 진수 C3 A9이며 이에 대한 o6f입니다. c3보다 큰 6f세 이하 그래서 C, 로케일 'béatrice' > 'boris'.

악센트가 아닙니다. 하이픈 넣기, 문장 부호 및와 같은 이상한 문자가있는 더 복잡한 규칙이 있습니다 œ. 모든 지역에서 이상한 문화적 규칙이 예상됩니다.

이제 비교할 문자열이 firstname다른 세계의 사람들 을위한 열을 가질 때와 같이 다른 언어를 혼합 하게되면 어쨌든 다른 언어의 다른 알파벳이 설계되지 않았기 때문에 특정 로케일이 지배해서는 안됩니다 서로에 대해 정렬.

이 경우 C합리적인 선택이며 순수한 바이트 비교를 능가하는 것은 없기 때문에 더 빠르다는 이점이 있습니다.

LC_CTYPE

갖는 LC_CTYPE'C'로 설정하는 것은 의미 같은 것을 C의 기능 isupper(c)또는 tolower(c)에만 US-ASCII 범위의 문자 예상 결과를 제공 (최대 유니 코드 코드 포인트에서 0x7f입니다).

SQL 기능이 좋아하기 때문에 upper(), lower()또는 initcap 이들의 libc 함수의 상단에 포스트 그레스에서 구현, 그들은 즉시 문자열의 US-ASCII 이외의 문자가 있기 때문에이 영향을하고 있습니다.

예:

test=> show lc_ctype;
  lc_ctype   
-------------
 fr_FR.UTF-8
(1 row)

-- Good result
test=> select initcap('élysée');
 initcap 
---------
 Élysée
(1 row)

-- Wrong result
-- collate "C" is the same as if the db has been created with lc_ctype='C'
test=> select initcap('élysée' collate "C");
 initcap 
---------
 éLyséE
(1 row)

를 들어 C로케일, éuncategorizable 문자로 처리됩니다.

정규식으로도 비슷한 결과를 얻을 수 있습니다.

test=> select 'élysée' ~ '^\w+$';
 ?column? 
----------
 t
(1 row)

test=> select 'élysée' COLLATE "C" ~ '^\w+$';
 ?column? 
----------
 f
(1 row)

따라서 내가 올바르게 이해하면 UTF-8 서버를 만들었더라도 주문 문제가 발생합니까? UTF-8에 LC_CTYPE 시스템을 설정하거나 UTF-8로 PostgreSQL을 컴파일하면 지정한 것과 동일한 비교 문제가 발생합니다.
Gregoire D.

이를 확장하기 위해 쿼리에 대해 콜레이트를 강제로 수행하여 비교가 로컬에서 옳을 수 있습니까?
Gregoire D.

예, 개별 문자열 비교에는이 답변에서와 같이 자체 조합 규칙을 포함 할 수 있습니다. collate "C" 애프터 order by. 응용 프로그램이 필요한지 여부와 장소를 결정하는 것은 사용자의 책임입니다. 대부분의 응용 프로그램은 실제로 신경 쓰지 않습니다.
Daniel Vérité

1
또한 개별 열에는 COLLATE데이터베이스와 다른 지정자가 있을 수 있습니다 .
Daniel Vérité

2
이 답변은 실제로 LC_CTYPE이 아니라 LC_COLLATE에 대한 것입니다. LC_CTYPE은 문자가 숫자, 문자, 공백, 문장 부호 등인지 판별하는 데 사용됩니다.
인지 판별 jjanes

10

데이터 정렬을 사용한 정렬에 대한 Daniel의 승인 된 답변과 관련하여 Mac에서 PostgreSQL을 실행하는 경우 운영 체제 수준에서 일부 데이터 정렬의 설정이 부적절하여 원하는 데이터 정렬이 예상대로 작동하지 않을 수 있습니다. 문제에 대한 자세한 내용은 여기를 참조하십시오.

http://www.postgresql.org/message-id/4B4E845F.80906@postnewspapers.com.au

이것은 특히 PostgreSQL 관련 문제가 아니라 데이터 정렬 설정에 대한 Mac의 기본 구성 문제입니다. 현재 시스템에서 OS X El Capitan 버전 10.11에서 PostgreSQL 9.3을 실행하고 있으며이 문제로 어려움을 겪고 있습니다. 내 시스템은 "fr_FR"또는 "en_US"데이터 정렬을 사용하는지 여부에 관계없이 동일한 쿼리 결과를 반환합니다. 예를 들면 다음과 같습니다.

"fr_FR"데이터 정렬 사용 :

select firstname from (values ('bernard'), ('bérénice'), ('béatrice'), ('boris'))
AS l(firstname)
order by firstname collate "fr_FR";

results:
==============
bernard
boris
béatrice
bérénice

“en_US”데이터 정렬 사용 :

select firstname from (values ('bernard'), ('bérénice'), ('béatrice'), ('boris'))
AS l(firstname)
order by firstname collate "en_US";

results:
==============
bernard
boris
béatrice
bérénice

내 시스템에서 데이터 정렬 설정 (운영 체제 수준)은 diff를 실행하여 셸에서 설명한“fr_FR”및“en_US”와 동일합니다.

cd /usr/share/locale
diff fr_FR.UTF-8/LC_COLLATE en_US.UTF-8/LC_COLLATE

이 추가 정보가이 문제로 어려움을 겪는 Mac에서 PostgreSQL을 사용하는 사람에게 도움이 되길 바랍니다.


최신 Mac에서 어떻게 작동시킬 수 있습니까? Mac에서 작동하도록하기 위해 어떤 작업을 수행 했습니까?
Dinesh Kumar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.