답변:
모든 행의 길이 가 같은 경우 일반적으로 CHAR을 선택 하십시오 . 선택 VARCHAR를 때 길이가 다릅니다 현저히. 모든 행의 길이가 동일하기 때문에 CHAR도 약간 빠를 수 있습니다.
DB 구현에 따라 다르지만 일반적으로 VARCHAR은 실제 데이터 외에 하나 또는 두 바이트 이상의 스토리지 (길이 또는 종료)를 사용합니다. 따라서 "FooBar"라는 단어를 저장하면 (1 바이트 문자 세트를 사용한다고 가정)
결론은 CHAR 이 상대적으로 동일한 길이의 데이터 (두 문자 길이 차이 내)에 대해 더 빠르고 공간 효율적일 수 있다는 것 입니다.
참고 : Microsoft SQL에는 VARCHAR에 대해 2 바이트의 오버 헤드가 있습니다. 이는 DB마다 다를 수 있지만 일반적으로 VARCHAR에서 길이 또는 EOL을 표시하는 데 필요한 최소 1 바이트의 오버 헤드가 있습니다.
주석에서 Gaven이 지적한 것처럼 UTF8과 같은 멀티 바이트 가변 길이 문자 세트를 사용하는 경우 CHAR은 문자 수를 저장하는 데 필요한 최대 바이트 수를 저장합니다. 따라서 UTF8이 문자를 저장하는 데 최대 3 바이트가 필요한 경우 latin1 문자 만 저장하더라도 CHAR (6)은 18 바이트로 고정됩니다. 따라서이 경우 VARCHAR이 훨씬 더 나은 선택이됩니다.
나와 함께 일하고 있고 Oracle과 함께 일하고 있다면 varchar
거의 모든 상황에서 사용하게 될 것입니다 . 실제 char
보다 처리 능력을 적게 사용 한다는 가정은 varchar
... 현재로서는 ... 데이터베이스 엔진은 시간이 지남에 따라 더 나아지고 이런 종류의 일반적인 규칙은 미래의 "신화"를 만들어냅니다.
또 다른 것은 : 누군가가 함께 가기로 결정했기 때문에 성능 문제를 본 적이 없습니다 varchar
. 좋은 코드 (데이터베이스에 대한 호출 횟수가 적음)와 효율적인 SQL (인덱스 작동 방법, 옵티마이 저가 결정을 내리는 방법, 평소 exists
보다 더 빠른 이유)을 작성하는 시간을 훨씬 더 잘 활용할 것입니다 in
.
최종 생각 : 나는 CHAR
``를 찾고 있어야 할 때 ''를 찾는 사람들 또는``FOO (여러 공간) ''를 찾아야 할 때``FOO ''를 찾는 사람들의 사용과 관련된 모든 종류의 문제를 보았습니다. 또는 후행 공백을 자르지 않는 사람 또는 Powerbuilder가 Oracle 프로 시저에서 리턴하는 값에 최대 2000 개의 공백을 추가하는 버그.
Char는 조금 더 빠르므로 알고있는 열이 일정 길이라면 char을 사용하십시오. 예를 들어 성별로 알려진 (M) ale / (F) emale / (U), 미국 주에서는 2자를 저장합니다.
NChar 또는 Char가 var 대안보다 성능이 우수합니까?
좋은 질문입니다. 특정 상황에서는 간단한 대답이 그렇습니다. 이것이 설명 될 수 있는지 봅시다.
분명히 우리는 varchar (255) 열로 테이블을 만들고 (이 열을 myColumn이라고 부릅니다) 백만 개의 행을 삽입하지만 각 행의 myColumn에 몇 문자 만 넣으면 테이블이 훨씬 작습니다 (전체) myColumn을 char (255)로 만든 경우보다 스토리지 엔진에 필요한 데이터 페이지 수). 해당 테이블에서 작업 (DML)을 수행하고 많은 행을 요청할 때마다 myColumn이 varchar 일 때 더 빠릅니다 . 마지막에 모든 "추가"공간 을 이동할 필요가 없기 때문 입니다. SQL Server가 고유 또는 통합 작업과 같은 내부 정렬을 수행하거나 쿼리 계획 등에서 병합을 선택하는 경우와 같이 이동합니다.
그러나 varchar를 사용하는 데 약간의 오버 헤드가 있습니다. SQL Server는 각 행에서 특정 행의 myColumn에 몇 바이트가 있는지 알기 위해 2 바이트 표시기 (오버 헤드)를 사용해야합니다. 문제를 나타내는 여분의 2 바이트가 아니라 모든 행에서 myColumn의 데이터 길이를 "디코딩"해야합니다.
내 경험상 쿼리에서 조인 될 열에 varchar 대신 char을 사용하는 것이 가장 좋습니다. 예를 들어 테이블의 기본 키 또는 인덱싱 될 다른 열입니다. 인구 통계 테이블의 CustomerNumber 또는 디코드 테이블의 CodeID 또는 주문 테이블의 OrderNumber입니다. char을 사용하면 쿼리 엔진은 포인터를 페이지를 읽을 때 가변적 인 양의 바이트로 이동하는 대신 포인터를 산술 연산 할 수 있기 때문에 조인을보다 빠르게 수행 할 수 있습니다. 나는 마지막 문장에서 당신을 잃었을 수도 있다는 것을 알고 있습니다. SQL Server의 조인은 "조건 자"라는 개념을 기반으로합니다. 술어는 조건입니다. 예를 들어, myColumn = 1 또는 OrderNumber <500입니다.
따라서 SQL Server가 DML 문을 수행하고 있고 결합되는 술어 또는 "키"가 고정 길이 (char) 인 경우 쿼리 엔진은 한 테이블의 행과 행의 행을 일치시키기 위해 많은 작업을 수행 할 필요가 없습니다. 다른 테이블. 행에 데이터가 얼마나 오래 있는지 알아 낸 다음 문자열을 걸어 끝을 찾습니다. 시간이 걸리는 모든 것.
이제 쉽게 구현하기가 어렵다는 점을 명심하십시오. 온라인 시스템에서 기본 키 필드에 char이 사용되는 것을 보았습니다. 너비는 작게 유지해야합니다 (예 : char (15) 또는 합리적인 것). 그리고 온라인 시스템에서 가장 잘 작동합니다. 일반적으로 적은 수의 행만 검색하거나 업스트림하기 때문에 결과 집합에서 얻을 수있는 후행 공백을 "트리밍"해야하는 것은 수백만의 행에 참여하는 것과 달리 사소한 작업입니다. 한 테이블에서 다른 테이블의 수백만 행에 이르는 행.
온라인 시스템에서 CHAR이 varchar보다 의미가있는 또 다른 이유는 페이지 분할이 줄어든다는 것입니다. char를 사용함으로써, 당신은 본질적으로 그 공간을 "예약"하고 (그리고 낭비), 사용자가 나중에 와서 그 열에 더 많은 데이터를 넣는다면 SQL은 이미 그 공간을 할당하고 그 안에 들어갑니다.
CHAR을 사용하는 또 다른 이유는 두 번째 이유와 유사합니다. 프로그래머 나 사용자가 수백만 행에 대해 "일괄 처리"업데이트를 수행하는 경우 예를 들어 메모 필드에 문장을 추가하면 야간에 DBA에서 드라이브가 가득 찬 이유에 대해 전화를받지 않습니다. 즉, 데이터베이스 크기가 더 예측 가능하게 증가합니다.
이것들은 온라인 (OLTP) 시스템이 char over varchar로부터 이익을 얻을 수있는 3 가지 방법입니다. 창고 / 분석 / OLAP 시나리오에서 char을 거의 사용하지 않습니다. 일반적으로 모든 char 열이 많은 낭비 된 공간에 추가 할 수있는 데이터가 너무 많기 때문입니다.
char은 데이터베이스를 훨씬 더 크게 만들 수 있지만 대부분의 백업 도구에는 데이터 압축 기능이 있으므로 varchar를 사용한 것처럼 백업 크기가 거의 같은 경향이 있습니다. 예를 들어 LiteSpeed 또는 RedGate SQL 백업입니다.
다른 용도는 데이터를 고정 폭 파일로 내보내기 위해 생성 된 뷰에서 사용됩니다. 메인 프레임에서 읽을 수 있도록 일부 데이터를 플랫 파일로 내 보내야한다고 가정 해 보겠습니다. 고정 너비입니다 (구분되지 않음). 내 "스테이징"테이블에 데이터를 varchar (따라서 데이터베이스의 공간을 덜 소비 함)로 저장 한 다음 뷰를 사용하여 해당 열의 고정 너비 너비에 해당하는 길이를 사용하여 모든 문자를 해당 문자와 동일하게 캐스팅합니다. . 예를 들면 다음과 같습니다.
create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )
insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)
create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))
SELECT * from vwStagingTable
내부적으로 varchar를 사용하기 때문에 내 데이터의 공간을 덜 차지하기 때문에 멋집니다. 그러나 DTS 또는 SSIS를 사용하거나 SSMS에서 메모장으로 잘라 붙여 넣기 만하면보기를 사용하고 올바른 수의 후행 공간을 얻을 수 있습니다. DTS에서 우리는 "가장 열"또는 무언가라고 불리는 것을 잊어 버렸습니다. SSIS에서는 더 이상이를 수행 할 수 없으므로 플랫 파일 연결 관리자를 신중하게 정의해야합니다. 그러나 뷰 설정이 있으므로 SSIS는 각 열의 너비를 알 수 있으며 데이터 흐름 작업을 작성할 때 많은 시간을 절약 할 수 있습니다.
결론은 ... varchar를 사용하십시오. char을 사용해야하는 이유는 매우 적으며 성능상의 이유 일뿐입니다. 수백만 행의 장애물이있는 시스템이있는 경우 술어가 결정적 (char)이지만 char을 사용하는 대부분의 시스템에서 단순히 공간을 낭비하는 경우 눈에 띄는 차이가 있습니다.
희망이 도움이됩니다. 제프
성능 이점이 있지만 여기에 언급되지 않은 행 마이그레이션이 있습니다. char를 사용하면 전체 공간을 미리 예약하므로 char (1000)이 있고 10자를 저장하면 1000 개의 문자 공간을 모두 사용하게됩니다. varchar2 (1000)에서는 10 자만 사용합니다. 데이터를 수정할 때 문제가 발생합니다. 900자를 포함하도록 열을 업데이트한다고 가정하겠습니다. varchar을 확장 할 공간이 현재 블록에서 사용 가능하지 않을 수 있습니다. 이 경우 DB 엔진은 행을 다른 블록으로 마이그레이션하고 원래 블록의 포인터를 새 블록의 새 행으로 만들어야합니다. 이 데이터를 읽으려면 이제 DB 엔진이 2 개의 블록을 읽어야합니다.
아무도 varchar 또는 char이 더 낫다고 말할 수 없습니다. 시간 균형을위한 공간이 있으며 특히 데이터가 증가 할 가능성이 높은 경우 데이터가 업데이트되는지 여부를 고려해야합니다.
열이 미국 상태 코드와 같은 고정 값을 저장하지 않는 한 varchar를 선택합니다. 항상 2 자 길이이며 유효한 미국 상태 코드 목록은 자주 변경되지 않습니다.)
다른 모든 경우에는 해시 된 암호 (고정 길이)를 저장하는 것처럼 varchar를 선택합니다.
이유 -char 유형 열은 항상 공백으로 처리되므로 my_column 열 은 char 내부에서 'ABC'값을 가진 char (5)로 정의됩니다.
my_column = 'ABC' -- my_column stores 'ABC ' value which is different then 'ABC'
그릇된.
이 기능 은 개발 과정에서 많은 자극적 인 버그로 이어질 수 있으며 테스트를 더 어렵게 만듭니다.
해당 필드의 모든 데이터 값이 동일한 길이 인 경우 CHAR은 VARCHAR보다 적은 저장 공간을 차지합니다. 아마도 2009 년에 VARCHAR을 CHAR로 변환 한 경우 800GB 데이터베이스는 모든 의도와 목적에 810GB와 동일하지만 짧은 문자열 (1 또는 2 자)의 경우 CHAR은 여전히 업계 최고의 모범 사례입니다.
이제 대부분의 데이터베이스가 정수 (비트, 작은, 정수, bigint)에 대해서만 제공하는 다양한 데이터 유형을 살펴보면 다른 것을 선택해야 할 이유가 있습니다. 매번 bigint를 선택하는 것은 실제로 현장의 목적과 용도에 대해 약간 무지합니다. 필드가 단순히 몇 년 된 사람을 나타내는 경우, bigint는 과잉입니다. 이제 반드시 "잘못된"것은 아니지만 효율적이지 않습니다.
그러나 그 흥미로운 주장은 시간이 지남에 따라 데이터베이스가 개선됨에 따라 CHAR 대 VARCHAR은 관련성이 적다는 주장 일 수 있습니다.
Jim McKeeth의 의견을 기다립니다.
또한 테이블에 CHAR 컬럼 만 있으면 인덱싱 및 전체 테이블 스캔이 더 빠릅니다. 기본적으로 옵티마이 저는 CHAR 컬럼 만있는 경우 각 레코드의 크기를 예측할 수 있으며 모든 VARCHAR 컬럼의 크기 값을 확인해야합니다.
VARCHAR 열을 이전 내용보다 큰 크기로 업데이트하는 경우 데이터베이스가 디스크에서 실제로 레코드를 이동하도록했기 때문에 데이터베이스가 인덱스를 다시 작성하도록 할 수 있습니다. CHAR 열을 사용하면 결코 발생하지 않습니다.
그러나 테이블이 크지 않으면 성능 저하에 신경 쓰지 않을 것입니다.
지크 스트라의 현명한 말을 기억하십시오. 조기 성능 최적화는 모든 악의 근원입니다.
CHAR
열 을 업데이트 할 때 인덱스도 업데이트해야합니다. VARCHAR 또는 CHAR 열을 업데이트하는 데 차이가 없습니다. 로 업데이트하는 FOO
것을 고려하십시오 BAR
.
나는 당신의 경우에 Varchar를 선택하지 않을 이유가 없다고 생각합니다. 그것은 당신에게 유연성을 제공하고 많은 응답자들이 언급했듯이, 성능은 매우 특별한 상황을 제외하고 (Google DBA와는 대조적으로) 필사자들은 그 차이를 알아 차리지 못할 정도입니다.
DB Types와 관련하여 주목할만한 흥미로운 점은 sqlite (꽤 인상적인 성능을 가진 인기있는 미니 데이터베이스)는 모든 것을 데이터베이스에 즉시 문자열 및 유형으로 넣는 것입니다.
나는 항상 VarChar를 사용하고 일반적으로 내가 필요로하는 것보다 훨씬 크게 만듭니다. 예 : 왜 안전하다고 말하지 않습니까?
나는 결코 문자를 사용하지 않을 것입니다. 나는 많은 사람들과이 논쟁을 벌였으며 그들은 항상 숯이 더 빠르다는 피곤한 진부한 생각을 불러 일으킨다. 글쎄, 얼마나 빨리? 우리는 여기에서 밀리 초, 몇 초에 대해 이야기하고 있습니까? 누군가가 몇 밀리 초 더 빨리 주장하기 때문에 시스템에 버그를 수정하기 위해 수많은 톤을 도입해야한다고 말하고 있습니까?
여기 몇 가지 문제가 있습니다.
모든 필드가 채워 지므로 언제 어디서나 RTRIMS가있는 코드로 끝납니다. 이것은 또한 더 긴 필드를 위해 엄청난 디스크 공간 낭비입니다.
이제 한 문자의 char 필드에 대한 전형적인 예가 있지만 필드는 선택 사항이라고 가정 해 봅시다. 누군가 빈 문자열을 해당 필드에 전달하면 하나의 공백이됩니다. 따라서 다른 응용 프로그램 / 프로세스가 쿼리 할 때 rtrim을 사용하지 않으면 단일 공간을 얻습니다. 우리는 xml 문서, 파일 및 기타 프로그램을 가지고 있으며 선택적 필드에 단 하나의 공간 만 표시하고 문제를 해결했습니다.
이제 char 필드에 빈 문자열이 아닌 null을 전달해야합니다. 그러나 이것이 null을 올바르게 사용하는 것은 아닙니다. 다음은 null을 사용하는 것입니다. 공급 업체로부터 파일을 얻습니다.
이름 | 성별 | 도시
밥 || 로스 앤젤레스
성별을 지정하지 않은 경우 Bob을 입력하고 테이블에 빈 문자열과 로스 앤젤레스를 입력하십시오. 이제 파일과 형식 변경을 가져오고 성별이 더 이상 포함되지 않았지만 과거에 있다고 가정 해 봅시다.
이름 | 도시
밥 | 시애틀
이제 성별이 포함되어 있지 않으므로 null을 사용합니다. Varchars는 문제없이 이것을 지원합니다.
반면에 Char은 다릅니다. 항상 null을 보내야합니다. 빈 문자열을 보내면 공백이있는 필드가됩니다.
나는 문자에서 그리고 약 20 년의 개발 기간 동안 내가 고쳐야했던 모든 버그를 계속 사용할 수있다.
분열. Char는 공간을 예약하고 VarChar는 공간을 예약하지 않습니다. varchar에 대한 업데이트를 수용하기 위해 페이지 분할이 필요할 수 있습니다.
CHAR
열을 업데이트 할 때 페이지 분할이 발생할 수 있습니다 .
일부 SQL 데이터베이스에서 VARCHAR은 오프셋을 최적화하기 위해 최대 크기로 채워집니다. 이는 전체 테이블 스캔 및 인덱스 속도를 높이기위한 것입니다.
이로 인해 CHAR (200)에 비해 VARCHAR (200)을 사용하여 공간을 절약 할 수 없습니다.
CHAR (NCHAR) 및 VARCHAR (NVARCHAR)을 사용하면 데이터베이스 서버가 데이터를 저장하는 방식이 다릅니다. 첫 번째는 후행 공백을 소개합니다. SQL SERVER 함수에서 LIKE 연산자와 함께 사용할 때 문제가 발생했습니다. 따라서 항상 VARCHAR (NVARCHAR)을 사용하여 안전하게 만들어야합니다.
예를 들어, TEST (ID INT, Status CHAR (1)) 테이블 이 있고 다음과 같은 특정 값을 가진 모든 레코드를 나열하는 함수를 작성하는 경우 :
CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'
이 함수에서 기본 매개 변수를 넣을 때 함수는 모든 행을 반환하지만 실제로는 그렇지 않습니다. @Status 데이터 형식을 VARCHAR로 변경하면 문제가 해결됩니다.