MySQL에서 SELECT 문의 기본 레코드 순서는 무엇입니까?


66

다음 표와 데이터가 있다고 가정하십시오.

create table t (
    k int,
    v int,
    index k(k)
    ) engine=memory;

insert into t (k, v)
values (10, 1),
       (10, 2),
       (10, 3);

select * from t where k = 10없이 발행하면 order byMySQL은 기본적으로 레코드를 어떻게 정렬합니까?

답변:


75

SQL Server에 대한 비슷한 질문에 대한 답변 을 다시 게시하십시오 .

SQL 세계에서 순서는 데이터 집합의 고유 속성이 아닙니다. 따라서 ORDER BY 절을 사용하여 데이터를 쿼리하지 않는 한 RDBMS에서 데이터가 특정 순서로 또는 심지어 일관된 순서로 다시 올 것이라는 보장은 없습니다.

따라서 귀하의 질문에 대답하십시오 :

  • MySQL은 일관성을 보장하지 않고 원하는 레코드를 정렬합니다.
  • 무엇이든이 주문에 의존 하려면을 사용하여 원하는 주문을 지정해야합니다 ORDER BY. 다른 일을하는 것은 반갑지 않은 놀라움에 대비하는 것입니다.

이것은 MySQL뿐만 아니라 모든 SQL의 속성입니다. SQL-92 스펙 의 관련 텍스트 는 다음과 같습니다.

<order by clause>가 지정되지 않은 경우 Q 행의 순서는 구현에 따라 다릅니다.

커서 스펙에 유사한 텍스트 비트가 있습니다.


26

ORDER BY절이 없는 행의 순서는 다음과 같습니다.

  • 두 저장소 엔진간에 다릅니다.
  • 동일한 스토리지 엔진을 사용하는 경우 동일한 스토리지 엔진의 두 버전간에 다를 수 있습니다. 예를 들어 , 아래로 스크롤하여 "행의 순서"
  • 스토리지 엔진 버전은 동일하지만 MySQL 버전이 다른 경우 해당 버전 간의 쿼리 최적화 프로그램 변경으로 인해 버전이 다를 수 있습니다.
  • 모든 것이 동일하면 달의 위상으로 인해 다를 수 있으며 괜찮습니다.

10

삽입은 순서가 맞지 않고 혼란 스럽습니다. 작성된 색인은 요소가 색인 인 링크 된 목록에서 적절한 위치에 삽입되는 순서를 갖습니다. 하나의 인덱스 요소에서 다음 인덱스 요소로의 순방향 이동 링크, ​​순회 및 무결성 목적을위한 역방향 링크 및 테이블의 실제 레코드에 대한 포인터 세트가있는 인덱스에 대한 3 중 링크리스트를 생각해보십시오. 해당 색인 요소와 일치합니다.

스토리지에 혼란스러운 실제 데이터. 보관 및 시공에서 주문한 데이터와 관련된 색인. 정렬되거나 정렬되지 않은 실제 데이터 풀은 관련된 쿼리에 따라 다릅니다.


4

MEMORY 스토리지 엔진에 관해서 는 기본 인덱스 레이아웃 HASH대신 BTREE인덱스 레이아웃의 측면이 사용되지 않기 때문에 순서가 삽입 순서대로 될 것으로 예상합니다 . k를 인덱싱하고 k는 동일한 값이므로 모든 키가 동일한 해시 버킷에 입력 됩니다. 해시 버킷을 채우는 데 추가 복잡성을 가정 할 이유가 없으므로 삽입 순서가 가장 적합합니다.

나는 동일한 샘플 테이블과 데이터를 가져 와서 30 INSERT초 동안 실행 했으며 이것을 얻었습니다.

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.00 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

k : 10 및 11에 대해 두 가지 다른 값을 추가하는 것을 테스트하기로 결정했습니다.

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t values
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

삽입 순서처럼 보입니다. k = 11은 10보다 먼저 해시 된 첫 번째 키입니다. 11 대신 10을 먼저 삽입하는 것은 어떻습니까? 이것이 내가 얻은 것입니다 :

mysql> use test
Database changed
mysql> drop table if exists t;
Query OK, 0 rows affected (0.02 sec)

mysql> create table t(k int, v int,index k(k)) engine=memory;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t values
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (11, 1), (11, 2), (11, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3),
    -> (10, 1), (10, 2), (10, 3), (10, 1), (10, 2), (10, 3);
Query OK, 30 rows affected (0.00 sec)
Records: 30  Duplicates: 0  Warnings: 0

mysql> select * from t;
+------+------+
| k    | v    |
+------+------+
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   11 |    1 |
|   11 |    2 |
|   11 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
|   10 |    1 |
|   10 |    2 |
|   10 |    3 |
+------+------+
30 rows in set (0.00 sec)

mysql>

만장일치입니다 !!! 삽입 순서가 정답입니다.

MEMORY 스토리지 엔진의 인덱스 사용에 대한 참고 사항

MEMORY에 대한 범위 검색은 비슷한 성능을 발휘합니다.

색인을 작성할 때 색인 USING BTREE정의와 함께 절을 지정할 수 있습니다 . 이것은 범위 쿼리를 개선합니다.

특정 행을 검색하면 HASH또는의 성능이 동일한 결과가 나타납니다 BTREE.

업데이트 2011-09-22 11:18 EDT

나는 오늘 흥미로운 것을 배웠다. Percona의 @Laurynas Biveinis 가 제공하는 링크를 읽었습니다 . Percona 링크는 MySQL 5.5.15의 MEMORY 테이블에 대해 알려줍니다 .

행 순서

ORDER BY가 없으면 레코드가 이전 MEMORY 구현과 다른 순서로 리턴 될 수 있습니다. 이것은 버그가 아닙니다. ORDER BY 절이없는 특정 주문에 의존하는 응용 프로그램은 예기치 않은 결과를 제공 할 수 있습니다. ORDER BY가없는 특정 순서는 스토리지 엔진 및 쿼리 옵티 마이저 구현의 부작용으로 마이너 MySQL 릴리스간에 변경 될 수 있습니다.

이것은 오늘 볼 수있는 좋은 링크였습니다. 내가 준 대답은 내가로드 한 테이블이 MySQL 5.5.12에서 오늘 예상되는 순서로 검색되었음을 보여줍니다. Percona와 @Laurynas Biveinis가 지적 했듯이 , 다른 부 릴리스에서는 보장되지 않습니다.

따라서 내 답변을 방어하기보다는 @Laurynas Biveinis 의 답변을 가장 최신 정보이기 때문에 홍보하고 싶습니다 . @Laurynas Biveinis를 위한 Kudos와 모자 떨어져 . 또한 질문에 대한 버전 별 답변을 홍보하지 않기로 정중하게 @eevar 에게 감사의 말씀 을 전합니다. 그들은 둘 다 오늘 내 공감대를 얻는다.

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