테이블의 열 순서에 대해 걱정할 이유가 있습니까?


84

FIRST와 AFTER를 사용하여 MySQL에서 열 순서를 변경할 수 있다는 것을 알고 있지만 왜 귀찮게하고 싶습니까? 좋은 쿼리는 데이터를 삽입 할 때 명시 적으로 열 이름을 지정하므로 테이블에서 열이 어떤 순서로되어 있는지 신경 쓸 이유가 있습니까?

답변:


94

열 순서는 Sql Server, Oracle 및 MySQL에 걸쳐 내가 조정 한 일부 데이터베이스에 큰 성능 영향을 미쳤습니다. 이 게시물에는 좋은 경험 규칙이 있습니다 .

  • 먼저 기본 키 열
  • 다음은 외래 키 열입니다.
  • 다음에 자주 검색되는 열
  • 나중에 자주 업데이트되는 열
  • Nullable 열은 마지막에 있습니다.
  • 더 자주 사용되는 nullable 열 이후 가장 적게 사용 된 nullable 열

성능 차이의 예는 인덱스 조회입니다. 데이터베이스 엔진은 인덱스의 일부 조건에 따라 행을 찾고 행 주소를 다시 가져옵니다. 이제 SomeValue를 찾고 있다고 가정하면 다음 표에 있습니다.

 SomeId int,
 SomeString varchar(100),
 SomeValue int

SomeString의 길이는 알 수 없기 때문에 엔진은 SomeValue가 시작되는 위치를 추측해야합니다. 그러나 순서를 다음과 같이 변경하는 경우 :

 SomeId int,
 SomeValue int,
 SomeString varchar(100)

이제 엔진은 SomeValue가 행 시작 후 4 바이트를 찾을 수 있음을 알고 있습니다. 따라서 열 순서는 성능에 상당한 영향을 미칠 수 있습니다.

편집 : Sql Server 2005는 행의 시작 부분에 고정 길이 필드를 저장합니다. 그리고 각 행에는 varchar의 시작에 대한 참조가 있습니다. 이것은 위에 나열된 효과를 완전히 무효화합니다. 따라서 최근 데이터베이스의 경우 열 순서가 더 이상 영향을 미치지 않습니다.


4
@TopBanana : varchars가 아니라 일반 char 열과 구별되는 것입니다.
Allain Lalonde

1
나는 테이블의 열 순서가 어떤 차이를 만들지 않는다고 생각합니다. 그것은 당신이 만들 수있는 INDEXES에 확실히 차이를 만듭니다. 사실입니다.
marc_s

4
@TopBanana : Oracle을 알고 있는지 여부는 확실하지 않지만 VARCHAR2 (100)에 대해 100 바이트를 예약하지 않습니다
Quassnoi

1
@Quassnoi : 가장 큰 영향은 nullable varchar () 열이 많은 테이블에서 Sql Server에 발생했습니다.
Andomar

7
이 답변의 URL은 더 이상 작동하지 않습니다. 대안이 있습니까?
scunliffe

41

최신 정보:

에서는 MySQL,이 작업을 수행 할 이유가있을 수 있습니다.

변수 데이터 유형 (예 :) VARCHAR은에 가변 길이로 저장 InnoDB되므로 데이터베이스 엔진은 각 행의 이전 열을 모두 탐색하여 해당 열의 오프셋을 찾아야합니다.

컬럼에 대한 영향은 17 % 까지 20클 수 있습니다.

자세한 내용은 내 블로그에서이 항목을 참조하십시오.

에서 Oracle, 후행 NULL열이 더 공간을 사용하지 당신은 항상 테이블의 끝에 넣어해야하는 이유, 그건.

또한에서 Oracle및에서 SQL Server큰 행의 경우 a ROW CHAINING가 발생할 수 있습니다.

ROW CHANING 하나의 블록에 맞지 않는 행을 분할하고 연결된 목록으로 연결된 여러 블록에 걸쳐 있습니다.

첫 번째 블록에 맞지 않는 후행 열을 읽으려면 연결 목록을 탐색해야하므로 추가 I/O작업 이 발생 합니다.

참조 이 페이지 의 그림 ROW CHAINING에서을 Oracle:

그렇기 때문에 자주 사용하는 열을 테이블의 시작 부분에 배치하고 자주 사용하지 않는 열 또는 인 경향이있는 열을 NULL테이블 끝에 배치해야합니다.

중요 사항:

이 답변이 마음에 들고 투표하고 싶다면 @Andomar의 답변에 투표하십시오 .

그는 똑같은 대답을했지만 아무런 이유없이 반대 투표를받은 것 같습니다.


1
그래서 이것이 느릴 것이라고 말하고 있습니다 : tinyTable에서 tinyTable.id, tblBIG.firstColumn, tblBIG.lastColumn을 선택하십시오. ) 조인은 동기식입니다 ... 그러나 이것은 빠릅니다 : select tinyTable.id, tblBIG.firstColumn from tinyTable 내부 조인 tblBIG on tinyTable.id = tblBIG.fkID 다른 블록에서 열을 사용하지 않으므로 아니요 연결된 목록을 탐색해야합니다.
jfrobishow

1
난 단지 6 %를 얻을, 그것은 대 COL1위한 어떤 다른 열입니다.
Rick James

6

이전 작업에서 Oracle 교육을 수행하는 동안 DBA는 nullable이 아닌 모든 열을 nullable 열 앞에 두는 것이 유리하다고 제안했습니다. TBH는 그 이유에 대한 자세한 내용을 기억하지 못합니다. 아니면 업데이트 될 가능성이있는 것이 마지막에 가야하는 것일까 요? (행이 확장되면 이동하지 않아도 될 수 있음)

일반적으로 아무런 차이가 없어야합니다. 말했듯이 쿼리는 "select *"의 순서에 의존하지 않고 항상 열 자체를 지정해야합니다. 나는 그것들을 변경할 수있는 DB를 모른다 ... 글쎄, 나는 당신이 그것을 언급 할 때까지 MySQL이 그것을 허용한다는 것을 몰랐다.


4
그는 옳았습니다. Oracle은 디스크에 후행 NULL 열을 쓰지 않아 일부 바이트를 절약합니다. dba-oracle.com/oracle_tips_ault_nulls_values.htm
Andomar

절대적으로 디스크 크기에 큰 차이를 만들 수 있습니다
Alex

그게 당신이 의미하는 링크입니까? 열 순서가 아닌 인덱스에서 null의 비 인덱싱과 관련이 있습니다.
araqnid

링크가 잘못되어 원본을 찾을 수 없습니다. 예를 들어 tlingua.com/new/articles/Chapter2.html
Andomar

5

잘못 작성된 일부 응용 프로그램은 열 이름 대신 열 순서 / 인덱스에 종속 될 수 있습니다. 그렇게해서는 안되지만 발생합니다. 열 순서를 변경하면 이러한 응용 프로그램이 중단됩니다.


3
자신의 코드를 테이블의 열 순서에 의존하도록 만드는 응용 프로그램 개발자는 응용 프로그램을 손상시킬 수 있습니다. 그러나 애플리케이션 사용자는 중단을 당할 자격이 없습니다.
spencer7593

4

입력해야 할 때 출력의 가독성 :

select * from <table>

데이터베이스 관리 소프트웨어에서?

아주 가짜 이유지만 지금은 아무것도 생각할 수 없습니다.


4

아니요, SQL 데이터베이스 테이블의 열 순서는 표시 / 인쇄 목적을 제외하고는 전혀 관련이 없습니다. 열을 재정렬 할 필요가 없습니다. 대부분의 시스템은이를 수행하는 방법도 제공하지 않습니다 (이전 테이블을 삭제하고 새 열 순서로 다시 만드는 경우 제외).

마크

편집 : 관계형 데이터베이스의 Wikipedia 항목에서 열 순서가 결코 문제 가 되지 않아야 함을 분명히 보여주는 관련 부분이 있습니다.

관계는 n- 튜플의 집합으로 정의됩니다. 수학 및 관계형 데이터베이스 모델 모두에서 집합은 항목 의 정렬되지 않은 컬렉션이지만 일부 DBMS는 데이터에 순서를 부과합니다. 수학에서 튜플은 순서를 가지며 복제를 허용합니다. EF Codd는 원래이 수학적 정의를 사용하여 튜플을 정의했습니다. 나중에 순서 대신 속성 이름을 사용하는 것이 관계 기반 컴퓨터 언어에서 (일반적으로) 훨씬 더 편리 할 것이라는 EF Codd의 훌륭한 통찰력 중 하나였습니다. 이 통찰력은 오늘날에도 여전히 사용되고 있습니다.


1
칼럼 차이가 내 눈에 큰 영향을 미치는 것을 보았 기 때문에 이것이 정답이라고 믿을 수 없습니다. 투표가 그것을 우선시하더라도. 흠.
Andomar

어떤 SQL 환경에 있습니까?
marc_s

1
내가 본 가장 큰 영향은 Sql Server 2000에 있었는데, 외래 키를 앞으로 이동하면 일부 쿼리의 속도가 2 ~ 3 배 빨라졌습니다. 이러한 쿼리에는 외래 키에 대한 조건으로 큰 테이블 스캔 (1M + 행)이있었습니다.
Andomar

5
RDBMS는 성능에 신경 쓰지 않는 한 테이블 순서에 의존하지 않습니다 . 다른 구현은 열 순서에 대해 다른 성능 패널티를 갖습니다. 거대하거나 작을 수 있으며 구현에 따라 다릅니다. 튜플은 이론적이며 RDBMS는 실용적입니다.
Esteban Küber

3
-1. 내가 사용한 모든 관계형 데이터베이스에는 일정 수준에서 열 순서가 있습니다. 표에서 *를 선택하면 열을 임의의 순서로 되 돌리지 않는 경향이 있습니다. 이제 온 디스크와 디스플레이는 다른 논쟁입니다. 데이터베이스의 실제 구현에 대한 가정을 뒷받침하기 위해 수학 이론을 인용하는 것은 말도 안됩니다.
DougW 2013 년

2

제가 생각할 수있는 유일한 이유는 디버깅과 소방입니다. "이름"열이 목록에서 약 10 번째로 나타나는 테이블이 있습니다. (1,2,3)의 id가있는 테이블에서 *를 빠르게 선택하고 이름을보기 위해 스크롤해야 할 때 고통 스럽습니다.

하지만 그게 다입니다.


1

종종 그렇듯이 가장 큰 요소는 시스템에서 작업해야하는 다음 사람입니다. 기본 키 열을 먼저, 외래 키 열을 두 번째로, 나머지 열을 시스템의 중요도 / 중요도 내림차순으로 설정하려고합니다.


일반적으로 마지막 열이 "생성"되는 것으로 시작합니다 (행이 삽입 될 때의 타임 스탬프). 물론 이전 테이블에서는 그 이후에 여러 열을 추가 할 수 있습니다. 가끔 복합 기본 키가 대리 키로 변경되어 기본 키가 여러 열에 걸쳐있는 테이블이 있습니다.
araqnid

1

UNION을 많이 사용하려는 경우 순서에 대한 규칙이 있으면 열을 쉽게 일치시킬 수 있습니다.


데이터베이스에 정규화가 필요한 것 같습니다! :)
James L

야! 다시 가져와, 내 데이터베이스를 말하지 않았어. :)
Allain Lalonde


두 테이블의 열 순서가 다른 순서로 UNION 할 수 있습니까?
Monica Heddneck

예, 테이블을 쿼리 할 때 명시 적으로 열을 지정하기 만하면됩니다. 테이블 A [a, b] B [b, a]에서는 (SELECT aa, ab FROM A) UNION (SELECT ba, bb FROM B)이 (SELECT * FROM A) UNION (SELECT * FROM B)의 안쪽에 있음을 의미합니다.
Allain Lalonde

1

언급했듯이 잠재적 인 성능 문제가 많이 있습니다. 쿼리에서 해당 열을 참조하지 않으면 끝에 매우 큰 열을 배치하면 성능이 향상되는 데이터베이스에서 작업 한 적이 있습니다. 레코드가 여러 디스크 블록에 걸쳐있는 경우 데이터베이스 엔진은 필요한 모든 열을 확보하면 블록 읽기를 중지 할 수 있습니다.

물론 성능에 미치는 영향은 사용중인 제조업체뿐만 아니라 잠재적으로 버전에 따라 크게 달라집니다. 몇 달 전에 Postgres가 "좋아요"비교를 위해 색인을 사용할 수 없다는 것을 알았습니다. 즉, " 'M %'와 같은 열"이라고 썼다면 M으로 건너 뛰고 첫 번째 N을 찾았을 때 종료하는 것이 현명하지 않았습니다. "사이"를 사용하도록 여러 쿼리를 변경할 계획이었습니다. 그런 다음 Postgres의 새 버전을 얻었고 같은 것을 지능적으로 처리했습니다. 쿼리를 변경하지 않아서 다행입니다. 분명히 여기서 직접적인 관련이 없지만 내 요점은 효율성을 고려하여 수행하는 모든 작업이 다음 버전에서 쓸모 없게 될 수 있다는 것입니다.

화면을 만들기 위해 데이터베이스 스키마를 읽는 일반 코드를 일상적으로 작성하기 때문에 열 순서는 거의 항상 저와 매우 관련이 있습니다. 마찬가지로 내 "레코드 편집"화면은 거의 항상 스키마를 읽고 필드 목록을 가져온 다음 순서대로 표시함으로써 구축됩니다. 열 순서를 변경해도 내 프로그램은 계속 작동하지만 표시가 사용자에게 이상 할 수 있습니다. 마찬가지로, 이름 / 주소 /시 /도 / 우편 번호가 아닌 도시 / 주소 / 우편 번호 / 이름 / 주가 표시됩니다. 물론 열의 표시 순서를 코드 나 제어 파일 등에 넣을 수는 있지만 열을 추가하거나 제거 할 때마다 제어 파일을 업데이트해야한다는 것을 기억해야합니다. 한 번 말하고 싶어요. 또한 편집 화면이 순전히 스키마에서 빌드되면 새 테이블을 추가하는 것은 편집 화면을 만들기 위해 코드를 0 줄로 작성하는 것을 의미 할 수 있습니다. (음, 좋습니다. 실제로는 일반적으로 일반 편집 프로그램을 호출하기 위해 메뉴에 항목을 추가해야합니다. 그리고 실용적으로 만들기에는 너무 많은 예외가 있기 때문에 일반적으로 일반 "업데이트 할 레코드 선택"을 포기했습니다. .)


1

명백한 성능 조정 외에도 열 순서를 다시 지정하면 (이전 기능) SQL 스크립트가 실패하는 코너 케이스가 발생했습니다.

문서에서 "TIMESTAMP 및 DATETIME 열은 명시 적으로 지정되지 않는 한 자동 속성이 없습니다.이 예외 : 기본적으로 첫 번째 TIMESTAMP 열에는 DEFAULT CURRENT_TIMESTAMP 및 둘 다 명시 적으로 지정되지 않은 경우 ON UPDATE CURRENT_TIMESTAMP가 있습니다 . " https : //dev.mysql .com / doc / refman / 5.6 / en / timestamp-initialization.html

따라서 ALTER TABLE table_name MODIFY field_name timestamp(6) NOT NULL;해당 필드가 테이블의 첫 번째 타임 스탬프 (또는 datetime)이면 명령 이 작동하지만 그렇지 않은 경우에는 작동하지 않습니다.

분명히, 기본값을 포함하도록 변경 명령을 수정할 수 있지만, 열 순서 변경으로 인해 작동하던 쿼리가 작동을 멈춘다는 사실 때문에 머리가 아팠습니다.


0

열 순서에 대해 걱정할 필요가있는 유일한 시간은 소프트웨어가 특별히 해당 순서에 의존하는 경우입니다. 일반적으로 이것은 개발자가 게으르고 a select *를 한 다음 결과에서 이름이 아닌 인덱스로 열을 참조 했기 때문입니다.


0

일반적으로 Management Studio를 통해 열 순서를 변경할 때 SQL Server에서 발생하는 일은 새 구조로 임시 테이블을 만들고 이전 테이블에서 해당 구조로 데이터를 이동하고 이전 테이블을 삭제하고 새 테이블의 이름을 변경하는 것입니다. 상상할 수 있듯이 테이블이 큰 경우 성능 측면에서 매우 열악한 선택입니다. 내 SQL이 같은 일을하는지 모르겠지만 우리 중 많은 사람들이 열 순서 변경을 피하는 이유 중 하나입니다. select *는 프로덕션 시스템에서 절대 사용해서는 안되므로 잘 설계된 시스템에서는 끝에 열을 추가하는 것이 문제가되지 않습니다. 테이블의 열 순서는 일반적으로 엉망이되어서는 안됩니다.


0

2002 년 Bill Thorsteinson은 열 순서를 변경하여 MySQL 쿼리를 최적화하기위한 제안을 Hewlett Packard 포럼에 게시했습니다. 그 이후로 그의 게시물은 인용없이 인터넷에서 문자 그대로 적어도 백 번 복사하여 붙여 넣었습니다. 그를 정확히 인용하자면 ...

일반적인 경험 법칙 :

  • 먼저 기본 키 열.
  • 다음은 외래 키 열입니다.
  • 다음은 자주 검색되는 열입니다.
  • 나중에 자주 업데이트되는 열.
  • Nullable 열은 마지막에 있습니다.
  • 더 자주 사용되는 Null 허용 열 이후 가장 적게 사용되는 Null 허용 열입니다.
  • 다른 열이 거의없는 자체 테이블의 Blob.

출처 : HP 포럼.

그러나 그 게시물은 2002 년에 완전히 돌아 왔습니다! 이 조언은 MySQL 5.1이 출시되기 6 년 전에 MySQL 버전 3.23에 대한 것입니다. 그리고 참고 문헌이나 인용이 없습니다. 그래서, 빌이 맞습니까? 이 수준에서 스토리지 엔진은 정확히 어떻게 작동합니까?

  1. 네, 빌이 옳았습니다.
  2. 그것은 모두 연결된 행과 메모리 블록의 문제로 귀결됩니다.

The Secrets of Oracle Row Chaining and Migration 에 대한 기사에서 Oracle 인증 전문가 인 Martin Zahn을 인용하려면 ...

연결된 행은 우리에게 다르게 영향을 미칩니다. 여기서는 필요한 데이터에 따라 다릅니다. 두 블록에 걸쳐있는 두 개의 열이있는 행이있는 경우 쿼리는 다음과 같습니다.

SELECT column1 FROM table

column1이 블록 1에있는 경우«table fetch continue row»가 발생하지 않습니다. 실제로 column2를 가져올 필요는 없으며 연결된 행을 끝까지 따르지 않습니다. 반면에 다음을 요청하는 경우 :

SELECT column2 FROM table

그리고 column2는 행 체인으로 인해 블록 2에 있으며 실제로«table fetch continue row»를 볼 수 있습니다.

기사의 나머지 부분은 꽤 잘 읽었습니다! 그러나 저는 여기서 우리의 질문과 직접적으로 관련된 부분만을 인용하고 있습니다.

18 년이 지난 지금, 나는 그것을 말해야합니다 : 감사합니다, 빌!

MySQL 행을 데이터 블록에 매핑

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.