MyISAM 및 InnoDB 비교


857

나는 많은 데이터베이스 쓰기를 포함하는 프로젝트를 진행하고 있다고 말합니다 ( 70 % 삽입 및 30 % 읽기 ). 이 비율에는 한 번의 읽기와 한 번의 쓰기로 간주되는 업데이트도 포함됩니다. 읽기가 더러울 수 있습니다 (예 : 읽을 때 100 % 정확한 정보가 필요하지 않습니다).
문제는 한 시간에 백만 건 이상의 데이터베이스 트랜잭션을 수행하는 것입니다.

웹에서 MyISAM과 InnoDB의 차이점에 대한 많은 자료를 읽었으며 MyISAM 은이 작업에 사용할 특정 데이터베이스 / 테이블에 대한 확실한 선택 인 것 같습니다. 내가 읽고있는 것부터 행 수준 잠금이 지원되므로 트랜잭션이 필요한 경우 InnoDB가 좋습니다.

이 유형의 하중 (또는 그 이상)에 경험이 있습니까? MyISAM이가는 길입니까?


13
MySQL의 성능 블로그는 것은 이러한 유형의 훌륭한 자원이다.
ceejayoz

3
이것은 시스템이 OLTP인지 또는 더 많은 데이터웨어 하우스 지향적인지에 달려 있습니다 (대부분의 쓰기는 벌크로드입니다).
nos

35
MyISAM은 행 잠금, 트랜잭션을 지원하지 않으며 외래 키도 지원하지 않습니다 ... 지옥, ACID를 제공 할 수 없기 때문에 적절한 데이터베이스로 간주 될 수 없습니다! 그렇기 때문에 InnoDB는 MySQL 5.5부터 기본 엔진이되었습니다. 그러나 어떤 이유로 MyISAM은 PhpMyAdmin 내에서 생성 된 테이블의 기본 엔진으로 계속 유지되므로 MyISAM에서 실행 된 이후 많은 아마추어 데이터베이스가 있습니다.
BlueRaja-대니 Pflughoeft


답변:


523

이 질문에 대해 간략히 설명 했으므로 InnoDB 또는 MyISAM 중 어떤 것을 사용할 것인지 결정할 수 있습니다 .

다음은 어떤 상황에서 어떤 DB 스토리지 엔진을 사용해야하는지에 대한 간단한 개요입니다.

                                                 MyISAM InnoDB
-------------------------------------------------- --------------
필요한 전체 텍스트 검색 예 5.6.4
-------------------------------------------------- --------------
거래 필요 예
-------------------------------------------------- --------------
자주 묻는 질문 예      
-------------------------------------------------- --------------
자주 삽입, 업데이트, 삭제 예
-------------------------------------------------- --------------
행 잠금 (단일 테이블에서 다중 처리) 예
-------------------------------------------------- --------------
관계형 기본 설계

요약

  • 거의 모든 상황에서 InnoDB 가 가장 좋은 방법입니다
  • 그러나 자주 읽지 않고 거의 글을 쓰지 않으면 MyISAM을 사용하십시오.
  • MySQL <= 5.5에서 전체 텍스트 검색, MyISAM 사용

11
InnoDB는 MySQL 5.6에서 전체 텍스트 인덱스를 가지고 있지만, 지금은 프로덕션 환경에서 사용할 준비가되지 않았습니다.
Bill Karwin

3
에 부여 12.9. 전체 텍스트 검색 기능 , "전체 텍스트 인덱스는 InnoDB 또는 MyISAM 테이블에서만 사용할 수 있습니다". MySQL> = 5.6에서는 OK 인 것처럼 보이지만 MySQL 5.5와 동일한 페이지에 여전히 "전체 텍스트 인덱스는 MyISAM 테이블에만 사용할 수 있습니다"라고 표시되어 있습니다. 위의 표는 MySQL 버전과 어떻게 다른지 알려주기 위해 업데이트 될 수 있습니다. 불행히도, 지금까지 MySQL 5.5가 표준으로 보입니다.
Hibou57

2
의 의미는 무엇입니까 : InnoDB - full-text: 5.6.4?? 예, 그렇지 않습니까?

2
MyISAM은 또한 행 개수를 내부적으로 저장합니다. 따라서 Count () 함수는 MyISAM에서 거의 무료 인 반면 InnoDB에서는 상당한 시간이 걸립니다.
Hedeshy

3
좋은 테이블이지만 품질과 안정성을위한 행을 추가하면 MyIsam = no, innoDB = yes가 더 나아질 것입니다.
pilavdzice

268

저는 데이터베이스 전문가가 아니며 경험을 바탕으로 이야기하지 않습니다. 하나:

MyISAM 테이블은 테이블 레벨 잠금을 사용합니다 . 예상 트래픽을 기반으로 초당 약 200 회의 쓰기가 가능합니다. MyISAM을 사용하면 언제든지이 중 하나만 진행할 수 있습니다 . 오버런을 피하기 위해 하드웨어가 이러한 트랜잭션을 유지할 수 있는지 확인해야합니다. 즉, 단일 쿼리는 5ms를 넘을 수 없습니다.

즉, InnoDB와 같은 행 수준 잠금을 지원하는 스토리지 엔진이 필요합니다.

반면에 각 스토리지 엔진의로드를 시뮬레이트하기 위해 몇 가지 간단한 스크립트를 작성한 다음 결과를 비교하는 것이 매우 간단합니다.


12
200에 가까워요? 평균 거래량이 2.5 건이면 [(2.5 * 1M) / 3600s =]가 700에 가까워집니다.
Ozzy

12
a single query can take no more than 5ms당신이 두 가지의 가능성이없는 가정 을 했기 때문에 나는 또한 동의하지 않습니다. A : 모든 쿼리에 동일한 테이블이 필요했습니다. & B : 사용 가능한 연결이 1 개뿐입니다! RAM이 높은 Linux 및 MySQL 5.5 설정은 최대 10,000 개의 동시 연결을 지원할 수 있음을 알려드립니다 ( dev.mysql.com/doc/refman//5.5/en/too-many-connections.html 참조 ).
Ozzy

152
테이블이 테이블 잠금이면 한 번에 하나의 쿼리 만 실행할 수 있습니다. 서버가 10000 개의 동시 연결을 지원하는지 여부는 중요하지 않으며, 테이블이 잠겨있는 동안 각각 백업됩니다.
Ryaner

2
또한 MyISAM은 공간 인덱스를 지원하지만 InnoDB는 지원하지 않습니다. 그리고 MyISAM은 외래 키를 생성하지 못하더라도 외래 키를 사용하지 않는 것 같습니다.
kriver

4
@kriver : MyISAM 테이블에 외래 키를 가질 수 없습니다. CREATE TABLE 문에 FK 정의를 포함시킬 수 있지만 정의 (간단히)는 무시됩니다.
ypercubeᵀᴹ

191

사람들은 종종 성능, 읽기 대 쓰기, 외래 키 등에 대해 이야기하지만 원자력 업데이트 라는 또 다른 견해로는 스토리지 엔진의 또 다른 필수 기능이 있습니다.

이 시도:

  1. 5 초가 걸리는 MyISAM 테이블에 대해 UPDATE를 발행하십시오.
  2. UPDATE가 진행되는 동안 (예 : 2.5 초) Ctrl-C를 눌러 중단하십시오.
  3. 테이블에 미치는 영향을 관찰하십시오. 몇 개의 행이 업데이트 되었습니까? 몇 개가 업데이트되지 않았습니까? 테이블을 읽을 수 있거나 Ctrl-C를 눌렀을 때 손상 되었습니까?
  4. InnoDB 테이블에 대해 UPDATE로 동일한 실험을 수행하여 진행중인 쿼리를 중단하십시오.
  5. InnoDB 테이블을 관찰하십시오. 제로 행이 업데이트되었습니다. InnoDB는 원자 업데이트를 보장했으며 전체 업데이트를 커밋 할 수없는 경우 전체 변경 사항을 롤백합니다. 또한 테이블이 손상되지 않았습니다. killall -9 mysqld충돌을 시뮬레이션하는 데 사용 하는 경우에도 작동합니다 .

물론 성능이 바람직하지만 데이터잃지 않는 것이 우선합니다.


4
레코드의 경우, ACISA 데이터베이스의 다른 특성 인 일관성, 격리 및 내구성은 MyISAM에서도 지원되지 않습니다.
Bill Karwin

CHECK TABLE에서와 같이 Control-C는 테이블을 손상시키지 않아야합니다. 모든 쿼리는 오류없이 진행됩니다. MyISAM은 모든 레코드를 업데이트하지 않고 업데이트를 중단하지만 테이블은 내부 구조 무결성을 유지합니다. SIGTERM으로 mysqld를 죽이면 같은 효과가 있습니다. 그러나 SIGKILL (kill -9) 또는 충돌 신호 (또는 버그에 부딪 칠 때 자체적으로 획득) 또는 OS 충돌 / 전원 손실이 발생하면 다른 이야기입니다. MyISAM 수준의 손상.
Sasha Pachev

1
InnoDB는 일반적으로 MyISAM보다 더 왕성하게 손상 될 수 있습니다. ACID의 아이러니는 우리가 전혀 또는 전혀 없다는 개념을 가지고 있다는 것입니다. 따라서 InnoDB가 모든 것을 제공 할 수없는 경우 내부 어설 션을 제공하지 않으며 일부 구조의 1 바이트가 잘못되어 전혀 실행을 거부합니다. 무시 될 수있는 시간의 90 %는 하나의 테이블에만 영향을 미칩니다. 최근 Percona 서버는이를 처리 할 수있는 옵션 (innodb_pass_corrupt_table)을 가지고 있습니다.
Sasha Pachev

1
지난 3 일 동안 이런 종류의 정보를 검색하고있었습니다. InnoDB가 최고입니다. 감사합니다Bill Karwin
user3833682

3
@ flow2k, 요즘 거의 없음. 마지막 작업에서 우리는 하나의 서버에서 하나의 테이블에 MyISAM을 사용했으며, 유일한 이유는 MyISAM이 해당 특정 테이블을 InnoDB보다 적은 공간에 저장할 수 있었기 때문입니다. 디스크 공간이 제한되어 있으므로 데이터베이스를 다른 서버로 옮길 때까지 MyISAM을 사용해야했습니다. 나의 새 직장에는 이미 모든 테이블이 InnoDB 여야한다는 정책이 있습니다.
Bill Karwin

138

MySQL을 사용하는 대용량 시스템에서 작업했으며 MyISAM과 InnoDB를 모두 시도했습니다.

MyISAM의 테이블 수준 잠금으로 인해 워크로드에 심각한 성능 문제가 발생하여 사용자와 유사한 것으로 나타났습니다. 불행히도 나는 또한 InnoDB의 성능이 기대보다 좋지 않다는 것을 알았습니다.

결국 삽입이 "핫"테이블로 이동하고 핫 테이블을 쿼리하지 않도록 선택하도록 데이터를 조각화하여 경합 문제를 해결했습니다.

이것은 또한 선택 쿼리에 의해 건드리지 않은 "stale"테이블에서 삭제 (데이터가 시간에 민감하고 X 일만 보존)를 허용했습니다. InnoDB는 대량 삭제시 성능이 떨어지는 것 같습니다. 따라서 데이터를 제거하려는 경우 오래된 데이터가 오래된 테이블에 삭제를 실행하는 대신 간단히 삭제할 수있는 방식으로 데이터를 구성 할 수 있습니다.

물론 응용 프로그램이 무엇인지 모르지만 MyISAM 및 InnoDB의 일부 문제에 대한 통찰력을 얻을 수 있기를 바랍니다.


3
"결국 삽입물이"핫 "테이블로 이동하고 선택하여 핫 테이블을 쿼리하지 않도록 데이터를 조각화하여 경합 문제를 해결했습니다." -본질적으로 버퍼 풀이 무엇 입니까?
BlueRaja-Danny Pflughoeft

15
대니-아뇨 서버 설정 조정은 중요하지만 스키마를 신중하게 구성하는 대신 사용할 수는 없습니다. 사용 가능한 RAM보다 훨씬 큰 DB가 있고 DB 전체에서 데이터를 무작위로 접촉하는 액세스 패턴이 있다면 세계의 모든 버퍼 풀 튜닝이 도움이되지 않습니다. 데이터와 액세스 패턴을 이해하면 신중한 디자인을 통해 많은 고통을 완화 할 수 있습니다.
alanc10n

66

게임에 조금 늦었지만 ... 여기 에 몇 달 전에 쓴 MYISAM과 InnoDB의 주요 차이점을 자세하게 설명한 포괄적 인 게시물이 있습니다. 컵파 (아마도 비스킷)를 잡고 즐기십시오.


MyISAM과 InnoDB의 주요 차이점은 참조 무결성과 트랜잭션에 있습니다. 잠금, 롤백 및 전체 텍스트 검색과 같은 다른 차이점도 있습니다.

참조 무결성

참조 무결성은 테이블 간의 관계가 일관되게 유지되도록합니다. 보다 구체적으로 말하면, 테이블 (예 : 리스팅)에 다른 테이블 (예 : 제품)을 가리키는 외래 키 (예 : 제품 ID)가 있고, 지정된 테이블에 대한 업데이트 또는 삭제가 발생하면 이러한 변경 사항이 연결에 연결됩니다. 표. 이 예에서 제품 이름이 바뀌면 연결 테이블의 외래 키도 업데이트됩니다. '제품'테이블에서 제품을 삭제하면 삭제 된 항목을 가리키는 모든 목록도 삭제됩니다. 또한 새 목록에는 유효한 기존 항목을 가리키는 외래 키가 있어야합니다.

InnoDB는 관계형 DBMS (RDBMS)이므로 참조 무결성이 있지만 MyISAM은 그렇지 않습니다.

거래 및 원 자성

테이블의 데이터는 SELECT, INSERT, UPDATE 및 DELETE와 같은 DML (Data Manipulation Language) 문을 사용하여 관리됩니다. 트랜잭션 그룹은 둘 이상의 DML 문을 단일 작업 단위로 함께 묶어 전체 단위가 적용되거나 전혀 적용되지 않습니다.

MyISAM은 트랜잭션을 지원하지 않지만 InnoDB는 지원합니다.

MyISAM 테이블을 사용하는 동안 작업이 중단되면 작업이 즉시 중단되고 작업이 완료되지 않은 경우에도 영향을받는 행 (또는 각 행 내의 데이터)이 영향을받습니다.

원 자성을 가진 트랜잭션을 사용하기 때문에 InnoDB 테이블을 사용하는 동안 작업이 중단되면 커밋이 수행되지 않으므로 완료되지 않은 트랜잭션은 적용되지 않습니다.

테이블 잠금 대 행 잠금

MyISAM 테이블에 대해 쿼리를 실행하면 쿼리하는 전체 테이블이 잠 깁니다. 이는 후속 쿼리가 현재 쿼리가 완료된 후에 만 ​​실행됨을 의미합니다. 큰 테이블을 읽거나 읽기 및 쓰기 작업이 자주 발생하는 경우 쿼리에 대한 백 로그가 엄청날 수 있습니다.

InnoDB 테이블에 대해 쿼리를 실행할 때 관련된 행만 잠기고 나머지 테이블은 CRUD 작업에 사용할 수 있습니다. 이는 동일한 행을 사용하지 않는 한 동일한 테이블에서 쿼리를 동시에 실행할 수 있음을 의미합니다.

InnoDB의이 기능은 동시성이라고합니다. 동시성이있는 한, 엄선 된 테이블 범위에 적용되는 주요 단점이 있습니다. 커널 스레드간에 전환하는 데 오버 헤드가 있으므로 서버가 중지되지 않도록 커널 스레드에 제한을 설정해야합니다. .

거래 및 롤백

MyISAM에서 작업을 실행하면 변경 사항이 설정됩니다. InnoDB에서는 이러한 변경 사항을 롤백 할 수 있습니다. 트랜잭션을 제어하는 ​​데 사용되는 가장 일반적인 명령은 COMMIT, ROLLBACK 및 SAVEPOINT입니다. 1. COMMIT-여러 DML 작업을 작성할 수 있지만 COMMIT가 수행 될 때만 변경 사항이 저장됩니다. 2. ROLLBACK-아직 커밋되지 않은 작업은 모두 버릴 수 있습니다. 3. SAVEPOINT-목록에서 포인트를 설정합니다. ROLLBACK 조작이 롤백 할 수있는 조작

신뢰할 수 있음

MyISAM은 데이터 무결성을 제공하지 않습니다. 하드웨어 오류, 부정한 종료 및 취소 된 작업으로 인해 데이터가 손상 될 수 있습니다. 인덱스와 테이블을 완전히 복구하거나 다시 작성해야합니다.

반면 InnoDB는 트랜잭션 로그, 이중 쓰기 버퍼 및 자동 체크섬 및 유효성 검사를 사용하여 손상을 방지합니다. InnoDB는 변경하기 전에 트랜잭션 이전의 데이터를 ibdata1이라는 시스템 테이블 스페이스 파일에 기록합니다. 충돌이 발생하면 InnoDB는 해당 로그 재생을 통해 자동 복구합니다.

전체 텍스트 인덱싱

InnoDB는 MySQL 버전 5.6.4까지 FULLTEXT 인덱싱을 지원하지 않습니다. 이 글을 쓰는 현재 많은 공유 호스팅 제공 업체의 MySQL 버전이 여전히 5.6.4 미만이므로 InnoDB 테이블에서 FULLTEXT 인덱싱이 지원되지 않습니다.

그러나 이것이 MyISAM을 사용하는 유효한 이유는 아닙니다. 최신 버전의 MySQL을 지원하는 호스팅 제공 업체로 변경하는 것이 가장 좋습니다. FULLTEXT 인덱싱을 사용하는 MyISAM 테이블을 InnoDB 테이블로 변환 할 수있는 것은 아닙니다.

결론

결론적으로 InnoDB는 기본 스토리지 엔진으로 선택해야합니다. 특정 요구에 맞는 MyISAM 또는 기타 데이터 유형을 선택하십시오.


나는 PHP 세션 체크섬 스크립트를 만들고 있었고 대부분의 키는 [az09]의 임의의 문자열 INSERT ON DUPLICATE KEY UPDATE입니다. innodb는 'unsortable'(무작위 문자열) 고유 키를 처리하기가 어렵습니다 ... 그에 대한 정보가 있습니까? 실제로 나는 그것이 MyISAM을 사용해야 할 영향에 대해 궁금해했지만 당신의 큰 대답은 그것이 그 특별한 경우에 갈 수있는 길이라는 것을 깨달았습니다.
Louis Loudog Trottier

64

더 많은 쓰기 및 읽기가있는로드의 경우 InnoDB의 이점이 있습니다. InnoDB는 테이블 잠금이 아닌 행 잠금을 제공하기 때문에 SELECT서로간에뿐만 아니라 많은로도 동시에 동기화 될 수 있습니다 INSERT. 그러나 SQL 트랜잭션을 사용하지 않으려면 InnoDB 커밋 플러시를 2 ( innodb_flush_log_at_trx_commit )로 설정하십시오. 이것은 테이블을 MyISAM에서 InnoDB로 옮길 때 잃어버린 많은 원시 성능을 다시 제공합니다.

또한 복제 추가를 고려하십시오. 이를 통해 약간의 읽기 조정이 가능하며 읽기가 최신 상태 일 필요는 없다고 언급 했으므로 복제가 약간 뒤쳐 질 수 있습니다. 교통량이 가장 많거나 항상 뒤쳐 질 수 있으며 절대로 뒤지지 않을 것입니다. 그러나이 방법으로 이동 하면 슬레이브 및 복제 지연 관리에서 데이터베이스 처리기로 읽기를 분리 하는 것이 좋습니다. 응용 프로그램 코드가 이것에 대해 알지 못하면 훨씬 간단합니다.

마지막으로, 다른 테이블로드에주의하십시오. 모든 테이블에서 동일한 읽기 / 쓰기 비율을 갖지는 않습니다. 100 %에 가까운 판독 값을 가진 일부 작은 테이블은 MyISAM을 유지할 수 있습니다. 마찬가지로 100 % 쓰기에 가까운 일부 테이블이있는 경우에는 이점이 INSERT DELAYED있지만 MyISAM에서만 지원됩니다 ( DELAYEDInnoDB 테이블 에서는이 절이 무시 됨).

그러나 벤치마킹해야합니다.


4
"InnoDB commit flush"는 당신이 말하는 것 innodb_flush_log_at_trx_commit입니까?
ceejayoz

2
게시물이 매우 유용하다는 것을 알았습니다. 감사합니다. 현재 내 테이블과 게시물에 MyISAM / InnoDB를 사용할시기를 평가하는 것이 도움이되었습니다. 건배.
starmonkey

2
dev.mysql.com/doc/refman/5.5/en/insert-delayed.html 상태 : MyISAM 테이블의 경우 데이터 파일 중간에 사용 가능한 블록이 없으면 동시 SELECT 및 INSERT 문이 지원됩니다. 이러한 상황에서는 MyISAM과 함께 INSERT DELAYED를 거의 사용하지 않아도됩니다.
tymtam

매우 유익한 게시물. 나는 op와 같은 질문을했고 당신의 게시물이 내 데이터베이스 엔진 결정에 대해 편안하게했다고 말해야합니다. 감사! ++
Joe Majewski

빠른 참고 사항 : 지연은 5.7에서 더 이상 지원되지 않습니다. 대신 LOW_PRIORITY로 테스트하고 싶을 수도 있습니다.
webmat

59

두 엔진 간의 기계적 차이를 다루는 다양한 응답을 추가하기 위해 경험적 속도 비교 연구를 제시합니다.

순수한 속도면에서, MyISAM이 InnoDB보다 빠른 경우는 아니지만 제 경험상 PURE READ 작업 환경에서는 약 2.0-2.5 배 더 빠릅니다. 다른 환경이 작성한 것처럼 MyISAM에는 트랜잭션 및 외래 키와 같은 기능이 없습니다.

아래에서 약간의 벤치마킹을 수행했습니다. 루핑에는 파이썬을 사용하고 타이밍 비교에는 timeit 라이브러리를 사용했습니다. 관심을 끌기 위해 메모리 엔진도 포함 시켰으므로 작은 테이블에만 적합하지만 The table 'tbl' is fullMySQL 메모리 제한을 초과 하면 계속 발생 합니다. 내가 본 네 가지 유형의 선택은 다음과 같습니다.

  1. 바닐라 선택
  2. 카운트
  3. 조건부 선택
  4. 인덱싱 및 인덱싱되지 않은 하위 선택

먼저 다음 SQL을 사용하여 세 개의 테이블을 만들었습니다.

CREATE TABLE
    data_interrogation.test_table_myisam
    (
        index_col BIGINT NOT NULL AUTO_INCREMENT,
        value1 DOUBLE,
        value2 DOUBLE,
        value3 DOUBLE,
        value4 DOUBLE,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8

두 번째 및 세 번째 테이블에서 'MyISAM'이 'InnoDB'및 'memory'로 대체되었습니다.

 

1) 바닐라 선택

질문: SELECT * FROM tbl WHERE index_col = xx

결과 : 추첨

다른 데이터베이스 엔진별로 바닐라 선택 비교

이것들의 속도는 대체로 동일하며, 예상되는 바와 같이 선택 될 열의 수는 선형입니다. InnoDB는 MyISAM보다 약간 빠르지 만 실제로는 미미합니다.

암호:

import timeit
import MySQLdb
import MySQLdb.cursors
import random
from random import randint

db = MySQLdb.connect(host="...", user="...", passwd="...", db="...", cursorclass=MySQLdb.cursors.DictCursor)
cur = db.cursor()

lengthOfTable = 100000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)
    cur.execute(insertString3)

db.commit()

# Define a function to pull a certain number of records from these tables
def selectRandomRecords(testTable,numberOfRecords):

    for x in xrange(numberOfRecords):
        rand1 = randint(0,lengthOfTable)

        selectString = "SELECT * FROM " + testTable + " WHERE index_col = " + str(rand1)
        cur.execute(selectString)

setupString = "from __main__ import selectRandomRecords"

# Test time taken using timeit
myisam_times = []
innodb_times = []
memory_times = []

for theLength in [3,10,30,100,300,1000,3000,10000]:

    innodb_times.append( timeit.timeit('selectRandomRecords("test_table_innodb",' + str(theLength) + ')', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('selectRandomRecords("test_table_myisam",' + str(theLength) + ')', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('selectRandomRecords("test_table_memory",' + str(theLength) + ')', number=100, setup=setupString) )

 

2) 카운트

질문: SELECT count(*) FROM tbl

결과 : MyISAM이 승리

다른 데이터베이스 엔진에 의한 카운트 비교

이것은 MyISAM과 InnoDB의 큰 차이점을 보여줍니다. MyISAM (및 메모리)은 테이블의 레코드 수를 추적 하므로이 트랜잭션은 빠르며 O (1)입니다. InnoDB가 계산하는 데 필요한 시간은 조사한 범위의 테이블 크기에 따라 선형 적으로 증가합니다. 실제로 관찰되는 MyISAM 쿼리의 많은 속도 향상이 비슷한 효과로 인한 것 같습니다.

암호:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to count the records
def countRecords(testTable):

    selectString = "SELECT count(*) FROM " + testTable
    cur.execute(selectString)

setupString = "from __main__ import countRecords"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('countRecords("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('countRecords("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('countRecords("test_table_memory")', number=100, setup=setupString) )

 

3) 조건부 선택

질문: SELECT * FROM tbl WHERE value1<0.5 AND value2<0.5 AND value3<0.5 AND value4<0.5

결과 : MyISAM이 승리

다른 데이터베이스 엔진 별 조건부 선택 비교

여기서 MyISAM과 메모리는 거의 동일하게 수행되며 더 큰 테이블의 경우 InnoDB를 약 50 % 이겼습니다. 이것은 MyISAM의 이점이 극대화 된 것으로 보이는 일종의 쿼리입니다.

암호:

myisam_times = []
innodb_times = []
memory_times = []

# Define a function to perform conditional selects
def conditionalSelect(testTable):
    selectString = "SELECT * FROM " + testTable + " WHERE value1 < 0.5 AND value2 < 0.5 AND value3 < 0.5 AND value4 < 0.5"
    cur.execute(selectString)

setupString = "from __main__ import conditionalSelect"

# Truncate the tables and re-fill with a set amount of data
for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE test_table_innodb"
    truncateString2 = "TRUNCATE test_table_myisam"
    truncateString3 = "TRUNCATE test_table_memory"

    cur.execute(truncateString)
    cur.execute(truncateString2)
    cur.execute(truncateString3)

    for x in xrange(theLength):
        rand1 = random.random()
        rand2 = random.random()
        rand3 = random.random()
        rand4 = random.random()

        insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
        insertString3 = "INSERT INTO test_table_memory (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)
        cur.execute(insertString3)

    db.commit()

    # Count and time the query
    innodb_times.append( timeit.timeit('conditionalSelect("test_table_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('conditionalSelect("test_table_myisam")', number=100, setup=setupString) )
    memory_times.append( timeit.timeit('conditionalSelect("test_table_memory")', number=100, setup=setupString) )

 

4) 하위 선택

결과 : InnoDB가 승리

이 쿼리에서는 하위 선택을위한 추가 테이블 세트를 작성했습니다. 각각은 기본 키 인덱스가 있고 다른 하나는 인덱스가없는 BIGINT의 두 열입니다. 큰 테이블 크기로 인해 메모리 엔진을 테스트하지 않았습니다. SQL 테이블 작성 명령은

CREATE TABLE
    subselect_myisam
    (
        index_col bigint NOT NULL,
        non_index_col bigint,
        PRIMARY KEY (index_col)
    )
    ENGINE=MyISAM DEFAULT CHARSET=utf8;

다시 한번, 'MyISAM'은 두 번째 테이블에서 'InnoDB'로 대체됩니다.

이 쿼리에서는 선택 테이블의 크기를 1000000으로 유지하고 대신 하위 선택된 열의 크기를 변경합니다.

다른 데이터베이스 엔진에 의한 하위 선택 비교

여기서 InnoDB는 쉽게 이깁니다. 합리적인 크기의 테이블에 도달하면 두 엔진 모두 하위 선택의 크기에 따라 선형으로 확장됩니다. 인덱스는 MyISAM 명령의 속도를 높이지만 흥미롭게도 InnoDB 속도에는 거의 영향을 미치지 않습니다. subSelect.png

암호:

myisam_times = []
innodb_times = []
myisam_times_2 = []
innodb_times_2 = []

def subSelectRecordsIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString = "from __main__ import subSelectRecordsIndexed"

def subSelectRecordsNotIndexed(testTable,testSubSelect):
    selectString = "SELECT * FROM " + testTable + " WHERE index_col in ( SELECT non_index_col FROM " + testSubSelect + " )"
    cur.execute(selectString)

setupString2 = "from __main__ import subSelectRecordsNotIndexed"

# Truncate the old tables, and re-fill with 1000000 records
truncateString = "TRUNCATE test_table_innodb"
truncateString2 = "TRUNCATE test_table_myisam"

cur.execute(truncateString)
cur.execute(truncateString2)

lengthOfTable = 1000000

# Fill up the tables with random data
for x in xrange(lengthOfTable):
    rand1 = random.random()
    rand2 = random.random()
    rand3 = random.random()
    rand4 = random.random()

    insertString = "INSERT INTO test_table_innodb (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"
    insertString2 = "INSERT INTO test_table_myisam (value1,value2,value3,value4) VALUES (" + str(rand1) + "," + str(rand2) + "," + str(rand3) + "," + str(rand4) + ")"

    cur.execute(insertString)
    cur.execute(insertString2)

for theLength in [3,10,30,100,300,1000,3000,10000,30000,100000]:

    truncateString = "TRUNCATE subselect_innodb"
    truncateString2 = "TRUNCATE subselect_myisam"

    cur.execute(truncateString)
    cur.execute(truncateString2)

    # For each length, empty the table and re-fill it with random data
    rand_sample = sorted(random.sample(xrange(lengthOfTable), theLength))
    rand_sample_2 = random.sample(xrange(lengthOfTable), theLength)

    for (the_value_1,the_value_2) in zip(rand_sample,rand_sample_2):
        insertString = "INSERT INTO subselect_innodb (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"
        insertString2 = "INSERT INTO subselect_myisam (index_col,non_index_col) VALUES (" + str(the_value_1) + "," + str(the_value_2) + ")"

        cur.execute(insertString)
        cur.execute(insertString2)

    db.commit()

    # Finally, time the queries
    innodb_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString) )
    myisam_times.append( timeit.timeit('subSelectRecordsIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString) )

    innodb_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_innodb","subselect_innodb")', number=100, setup=setupString2) )
    myisam_times_2.append( timeit.timeit('subSelectRecordsNotIndexed("test_table_myisam","subselect_myisam")', number=100, setup=setupString2) )

이 모든 것의 핵심 메시지는 속도에 정말로 관심 이 있다면 어떤 엔진이 더 적합한 지에 대한 가정을하기보다는 수행중인 쿼리를 벤치 마크해야한다는 것입니다.


1
항상 성능 만 고려하는 것은 아닙니다. 안정성에 대한 그래프는 어떻습니까? 엔진은 충돌하고 기본 데이터베이스 기능을 지원하지 않는 경우 아무 것도 좋지 않습니다.
pilavdzice 2016 년

1
my.cnf파일이 InnoDB에 최적화되어 있지 않으면 MyISAM이 아마도 대부분 InnoDB를 능가했을 것입니다 . my.cnf파일이 어떻게 생겼는지 언급하지 않았는데 , 이는 실제로 InnoDB 성능에 가장 중요한 요소입니다.
itoctopus

고마워요 itoctopus-나는 당신이 추천하는 최적화에 대해 더 많이 듣고 싶습니다. 이 테스트에 사용 된 전체 코드는 위에 있으며 다양한 최적화를 통해 실험을 반복하고 결과에 중대한 변화가 있는지 알려주십시오.
StackG

32

주제를 약간 벗어 났지만 문서화 목적과 완전성을 위해 다음을 추가하고 싶습니다.

일반적으로 InnoDB를 사용하면 LESS가 훨씬 복잡한 응용 프로그램이 만들어지며 아마도 버그가 없을 것입니다. 모든 참조 무결성 (외부 키 제약 조건)을 데이터 모델에 넣을 수 있으므로 MyISAM에 필요한만큼 많은 응용 프로그램 코드가 필요하지 않습니다.

레코드를 삽입, 삭제 또는 교체 할 때마다 관계를 확인하고 유지해야합니다. 예를 들어 부모를 삭제하면 모든 자식도 삭제해야합니다. 예를 들어, 간단한 블로그 시스템에서도 블로그 게시 레코드를 삭제하면 주석 레코드 등을 삭제해야합니다. InnoDB에서는 데이터베이스 엔진에 의해 자동으로 수행됩니다 (모델에 제약 조건을 지정한 경우) )이며 애플리케이션 코드가 필요하지 않습니다. MyISAM에서는 웹 서버에서 매우 어려운 응용 프로그램으로 코딩해야합니다. 웹 서버는 본질적으로 매우 동시 적 / 병렬 적이며 이러한 작업은 원자 적이어야하고 MyISAM은 실제 트랜잭션을 지원하지 않기 때문에 웹 서버에 MyISAM을 사용하면 위험하고 오류가 발생하기 쉽습니다.

또한 대부분의 경우 InnoDB는 여러 가지 이유로 테이블 수준 잠금과 달리 레코드 수준 잠금을 사용할 수있는 여러 가지 이유로 성능이 훨씬 향상됩니다. 쓰기가 읽기보다 빈번한 상황뿐만 아니라 대규모 데이터 세트에서 복잡한 조인이있는 상황에서도 가능합니다. 우리는 MyISAM 테이블보다 InnoDB 테이블을 사용하여 매우 큰 조인 (몇 분 소요)으로 3 배의 성능 향상을 발견했습니다.

MySQL을 사용할 때 일반적으로 InnoDB (참조 무결성이 완전한 3NF 데이터 모델 사용)가 기본 선택이어야한다고 말하고 싶습니다. MyISAM은 매우 특정한 경우에만 사용해야합니다. 성능이 낮을수록 응용 프로그램이 더 크고 더 버그가 있습니다.

이 말을했다. 데이터 모델링은 웹 디자이너 / 프로그래머들 사이에서 드물게 발견되는 기술입니다. 범죄는 없지만 MyISAM이 많이 사용되는 것을 설명합니다.


31

InnoDB는 다음을 제공합니다.

ACID transactions
row-level locking
foreign key constraints
automatic crash recovery
table compression (read/write)
spatial data types (no spatial indexes)

InnoDB에서 TEXT 및 BLOB를 제외한 행의 모든 ​​데이터는 최대 8,000 바이트를 차지할 수 있습니다. InnoDB에 대한 전체 텍스트 인덱싱이 없습니다. InnoDB에서 COUNT (*) (WHERE, GROUP BY 또는 JOIN을 사용하지 않는 경우)는 행 수가 내부적으로 저장되지 않기 때문에 MyISAM보다 느리게 실행됩니다. InnoDB는 데이터와 인덱스를 모두 하나의 파일에 저장합니다. InnoDB는 버퍼 풀을 사용하여 데이터와 인덱스를 모두 캐시합니다.

MyISAM은 다음을 제공합니다.

fast COUNT(*)s (when WHERE, GROUP BY, or JOIN is not used)
full text indexing
smaller disk footprint
very high table compression (read only)
spatial data types and indexes (R-tree)

MyISAM에는 테이블 수준 잠금이 있지만 행 수준 잠금은 없습니다. 거래가 없습니다. 자동 응급 복구는 없지만 복구 테이블 기능을 제공합니다. 외래 키 제약 조건이 없습니다. MyISAM 테이블은 일반적으로 InnoDB 테이블과 비교할 때 디스크 크기가 더 작습니다. 필요한 경우 myisampack으로 압축하여 MyISAM 테이블의 크기를 크게 줄일 수 있지만 읽기 전용이됩니다. MyISAM은 한 파일에 인덱스를 저장하고 다른 파일에 데이터를 저장합니다. MyISAM은 인덱스 캐싱에 키 버퍼를 사용하고 데이터 캐싱 관리를 운영 체제에 맡깁니다.

전반적으로 나는 대부분의 목적으로 InnoDB를 권장하고 특수 용도로는 MyISAM을 권장합니다. InnoDB는 이제 새로운 MySQL 버전의 기본 엔진입니다.


2
fnow, InnoDB의 VARCHAR은 BLOB 및 TEXT와 같이 오버플로 페이지로 이동할 수도 있습니다. 이러한 모든 데이터 유형은 내부적으로 유사하게 저장됩니다.
Bill Karwin

알아서 반가워, @BillKarwin! 우리는 앱에서 VARCHAR을 많이 사용하고 있으며 VARCHAR이 ~ 8kB 한계에 기여하는 것은 약간 걱정이었습니다.
rinogo

자세한 내용은 mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb 를 참조하십시오.
Bill Karwin

현재 MySQL 버전 5.6+의 innodb 엔진은 전체 텍스트 인덱싱을 지원 하고 MySQL 5.5 + / 5.7 +는 공간 데이터 유형 (5.5+)공간 인덱스 (r-tee) (5.7+)를 지원하므로 대답이 최신 상태가 아닙니다. .. 최선의 지원을 당신이어야 5.7 이상 MySQL 버전을해야합니다
레이몬드 Nijland을

25

당신의 MyISAM을 사용하는 경우, 당신은 일을하지 않습니다 어떤 당신은 (어떤 경우에, 충돌의 경우에 내구성이나 원자되지 않습니다) 거래를 할 각 DML 문을 고려하지 않는 한, 시간당 트랜잭션을.

따라서 InnoDB를 사용해야한다고 생각합니다.

초당 300 건의 트랜잭션이 상당히 많이 들립니다. 정전시에도 이러한 트랜잭션이 내구성이 있어야한다면 I / O 하위 시스템이 초당 많은 쓰기 작업을 쉽게 처리 할 수 ​​있어야합니다. 최소한 배터리 백업 캐시가있는 RAID 컨트롤러가 필요합니다.

약간의 내구성에 영향을 줄 수있는 경우 innodb_flush_log_at_trx_commit을 0 또는 2로 설정하여 InnoDB를 사용할 수 있습니다 (자세한 내용은 문서 참조).

Google 및 기타 업체의 동시성을 높일 수있는 여러 패치가 있습니다. 패치가 없으면 성능이 충분하지 않은 경우 관심을 가질 수 있습니다.


24

질문과 대부분의 답변이 오래되었습니다 .

예, MyISAM이 InnoDB보다 빠르다는 것은 오래된 아내들의 이야기입니다. 질문 날짜를 확인하십시오 : 2008; 이제는 거의 10 년 후입니다. InnoDB는 그 이후로 상당한 성능 향상을 이루었습니다.

: 극적인 그래프의 MyISAM가 승리 한 경우를했다 COUNT(*) 없이WHERE 절. 하지만 정말 시간을 보내고 있습니까?

동시성 테스트 를 실행하면 InnoDB가 에 대해MEMORY 이길 가능성이 높습니다 .

벤치마킹하는 동안 쓰기를 수행하면 SELECTsMyISAM 및 MEMORY테이블 수준 잠금으로 인해 손실 될 수 있습니다.

실제로 Oracle은 InnoDB가 8.0에서 MyISAM을 제외한 나머지를 모두 사용하는 것이 좋습니다.

질문 은 5.1 일 초에 작성되었습니다. 그 이후로이 주요 버전은 "일반 가용성"으로 표시되었습니다.

  • 2010 년 5.5 (12 월 0.8)
  • 2013 년 : 5.6 (2 월에 10.10)
  • 2015 년 : 5.7 (10 월 9 일)
  • 2018 년 8.0 (4 월 11 일)

결론 : MyISAM을 사용하지 마십시오


2
MySQL 데이터베이스 기술 발전. 그리고 StackOverflow 질문과 답변은 과거에도 여전히 기뻐합니다. 주요 의 MyISAM과 InnoDB의 차이는 적은 서버의 "로드"에 대해, 그리고 지원에 대한 참조 무결성거래 뿐만 아니라, 동시성복구 (10)
spencer7593

12

또한 MySQL 자체의 대체 대체품도 확인하십시오.

MariaDB

http://mariadb.org/

MariaDB는 MySQL을위한 드롭 인 대체 기능을 제공하는 데이터베이스 서버입니다. MariaDB는 광범위한 자유 및 오픈 소스 소프트웨어 개발자 커뮤니티의 도움을 받아 MySQL의 최초 작성자 중 일부가 작성했습니다. MariaDB는 MySQL의 핵심 기능 외에도 대체 스토리지 엔진, 서버 최적화 및 패치를 포함하여 다양한 기능 향상 기능을 제공합니다.

퍼 코나 서버

https://launchpad.net/percona-server

성능 향상, 진단 개선 및 기능 추가로 MySQL의 향상된 드롭 인 대체품.


1
나는 둘 다 사용하고 있습니다 (Percona는 프로덕션 환경, Maria는 Windows 개발 환경). 그들은 더 빠르고 ar을 완벽하게 작동합니다.
Moshe L

4
이것은 질문에 대답하지 않습니다. MariaDB 및 Percona는 MySQL의 포크이며 InnoDB 및 MyISAM 엔진도 사용합니다.
dr_

12

유의하시기 바랍니다 내가 오라클에 해당하지만, MySQL을 위해 진실하지 않은 것을 말 그렇다면, MySQL은 내 작품은 전적으로 개인과 내 자신의 시간에하고있는 동안 내 정규 교육과 경험, 오라클 것을, 나는 사과드립니다. 두 시스템은 많은 것을 공유하지만 관계 이론 / 대수는 동일하며 관계형 데이터베이스는 여전히 관계형 데이터베이스이지만 여전히 많은 차이점이 있습니다 !!

특히 InnoDB가 트랜잭션 기반이라는 점은 행 수준 잠금뿐 아니라 웹 응용 프로그램의 "작동"한 번에 대해 여러 번 업데이트 / 삽입 / 생성 / 변경 / 삭제 / 등을 수행 할 수 있음을 의미합니다. 발생하는 문제 는 이러한 변경 / 작업 중 일부만 커밋되지만 나머지는 그렇지 않은 경우 대부분의 경우 (데이터베이스의 특정 디자인에 따라) 데이터 / 구조가 충돌하는 데이터베이스로 끝날 것입니다.

참고 : Oracle에서는 create / alter / drop 문을 "DDL"(데이터 정의) 문이라고하며 커밋을 암시 적으로 트리거합니다. "DML"(데이터 조작)이라는 삽입 / 업데이트 / 삭제 명령문은 자동으로 커밋 되지 않지만 DDL, 커밋 또는 종료 / 종료가 수행 될 때 (또는 세션을 "자동 커밋"으로 설정 한 경우에만) 또는 클라이언트가 자동 커밋하는 경우). Oracle을 사용할 때이를 알고 있어야하지만, MySQL이 두 가지 유형의 명령문을 어떻게 처리하는지 잘 모르겠습니다. 이 때문에 MySQL에 관해서는 확실하지 않다는 것을 분명히하고 싶습니다. 오직 오라클에서만 가능합니다.

트랜잭션 기반 엔진이 탁월한 경우의 예 :

무료 이벤트에 참석하기 위해 본인 또는 귀하가 웹 페이지에 등록하고 있으며이 시스템의 주요 목적 중 하나는 최대 100 명까지만 가입 할 수있게하는 것입니다. 이벤트. 가입이 100 회에 도달하면 시스템은 다른 사용자가 취소 할 때까지 추가 가입을 비활성화합니다.

이 경우 손님 용 테이블 (이름, 전화 번호, 전자 메일 등)과 가입 한 손님 수를 추적하는 두 번째 테이블이있을 수 있습니다. 따라서 하나의 "트랜잭션"에 대해 두 가지 작업이 있습니다. 게스트 정보가 GUESTS 테이블에 추가 된 후 연결이 끊어 지거나 같은 영향을주는 오류가 있다고 가정합니다. GUESTS 테이블이 업데이트 (삽입)되었지만 "사용 가능한 좌석"을 업데이트하기 전에 연결이 끊어졌습니다.

이제 손님 테이블에 손님이 추가되었지만 사용 가능한 좌석 수가 잘못되었습니다 (예 : 실제로 84 인 경우 값은 85 임).

물론 이 테이블을 처리하는 방법에는 "객실 테이블에서 행에서 100을 뺀 행 수"를 사용하여 사용 가능한 좌석을 추적하거나 정보가 일관성이 있는지 확인하는 코드 등이 있습니다. 그러나 트랜잭션 기반 데이터베이스 같은 이노로, 중 엔진 ALL 작업의 커밋 또는되는 NONE 중은 없습니다. 이것은 많은 경우에 도움이 될 수 있지만, 내가 말했듯이 안전하지 않는 유일한 방법은 아닙니다 (그러나 프로그래머 / 스크립트 작성자가 아닌 데이터베이스가 처리하는 좋은 방법입니다).

그것은 "트랜잭션 기반"이라는 것이 본질적으로이 문맥에서 의미하는 바가 있습니다. 만약 내가 빠진 것이 아니라면 전체 트랜잭션이 성공적으로 이루어 지거나 아무것도 변경 되지 않는다는 것입니다. 데이터베이스, 아마도 그것을 손상시킬 수도 있습니다 ...

그러나 한 번 더 말하겠습니다. 혼란을 피하는 유일한 방법은 아닙니다. 그러나 그것은 엔진 자체가 처리하는 방법 중 하나입니다. "트랜잭션이 성공적 이었는지 아닌지, 그리고 수동이 아닌 (재시도 등) 그렇지 않은 경우 어떻게해야합니까?" 데이터베이스 외부에서 "수동으로"확인하기위한 코드 작성 및 이러한 이벤트에 대해 더 많은 작업 수행

마지막으로 테이블 잠금과 행 잠금에 대한 참고 사항 :

면책 조항 : MySQL과 관련하여 다음과 같은 모든 것에 잘못이있을 수 있으며 가설 / 예제 상황을 살펴볼 것이지만 MySQL로 손상을 일으킬 수 있는 것은 정확히 틀릴 수 있습니다 . 그러나 MySQL이 그러한 것들을 피할 수있는 더 많은 메커니즘이 있더라도 일반적인 프로그래밍에서 예제는 매우 실제적입니다 ...

어쨌든, 나는 한 번에 몇 개의 연결이 허용되는지 잠긴 테이블 주위에서 작동 하지 않는다고 주장한 사람들에 동의하는 데 상당히 확신 합니다. 실제로 여러 연결 이 테이블을 잠그는 전체 지점입니다 !! 따라서 다른 프로세스 / 사용자 / 앱은 동시에 변경하여 데이터베이스를 손상시킬 수 없습니다.

같은 행에서 작동하는 둘 이상의 연결이 어떻게 당신을 위해 정말 나쁜 날이 될까요? 동일한 행에서 동일한 값을 업데이트하고자하는 두 개의 프로세스가 있다고 가정합니다. 행이 버스 투어의 레코드이므로 두 프로세스가 동시에 "라이더"또는 "available_seats"를 업데이트하려고한다고 가정하겠습니다. "현재 값에 1을 더한 값"으로

이 단계를 단계별로 가정하여 봅시다 :

  1. 프로세스 1은 현재 값을 읽습니다. 비어 있다고 가정하여 지금까지 '0'이라고 가정 해 봅시다.
  2. 프로세스 2는 현재 값도 읽습니다. 여전히 0입니다.
  3. 프로세스 1은 (현재 + 1) 1입니다.
  4. 프로세스 2 2를 작성 해야 하지만 프로세스 1은 새 값을 쓰기 전에 현재 값을 읽으므로 1도 테이블에 씁니다.

나는 두 개의 연결이 첫 번째 쓰기 전에 읽는 것과 같이 섞일 수 있다고 확신하지 못합니다 . 그러나 그렇지 않다면 여전히 다음과 같은 문제가 있습니다.

  1. 프로세스 1은 현재 값인 0을 읽습니다.
  2. 프로세스 1 쓰기 (현재 + 1), 즉 1
  3. 프로세스 2는 현재 값을 읽습니다. 그러나 하나의 DID 쓰기 (업데이트)를 처리하는 동안 데이터를 커밋하지 않았으므로 동일한 프로세스 만 업데이트 된 새 값을 읽을 수 있지만 다른 모든 프로세스는 커밋이있을 때까지 이전 값을 볼 수 있습니다.

또한 최소한 Oracle 데이터베이스에는 격리 수준이 있으며, 이는 패러 프레이즈를 시도하는 데 시간을 낭비하지 않습니다. 다음은 그 주제에 대한 좋은 기사와 장단점이있는 각 격리 수준이며 데이터베이스에 트랜잭션 기반 엔진이 얼마나 중요한지 설명합니다.

마지막으로, 외래 키 및 트랜잭션 기반 상호 작용 대신 MyISAM 내에 다른 보호 수단이있을 수 있습니다. 우선, 전체 테이블이 잠기므로 트랜잭션 / FK가 필요할 가능성이 줄어 듭니다 .

그리고 아아, 이러한 동시성 문제를 알고 있다면 안전하지 않고 응용 프로그램을 작성하고 그러한 오류가 발생하지 않도록 시스템을 설정하십시오 (데이터베이스 자체가 아니라 코드가 책임집니다). 그러나 필자의 의견으로는 가능한 한 많은 수의 보호 장치를 사용하여 방어 적으로 프로그래밍하고 사람의 실수를 완전히 피하는 것이 불가능하다는 것을 항상 인식하는 것이 가장 좋습니다. 모든 사람에게 발생하며, 면역이 있다고 말하는 사람은 거짓말을하거나 "Hello World"응용 프로그램 / 스크립트를 작성하는 것 이상을하지 않아야합니다. ;-)

나는 그 중 일부가 어떤 사람에게 도움이되기를 바랍니다. 더 나아가서, 나는 지금 막 가정의 범인이 아니고 실수로 인간이 아니었기를 바랍니다. 그렇다면 사과드립니다. 그러나 이러한 특정 상황에서 가능성이없는 경우에도 그 예를 생각해보고, 위험을 조사하는 등의 방법이 좋습니다.

저를 바로 고치고,이 "답변"을 편집하고, 심지어 투표하십시오. 다른 사람과 나의 잘못된 가정을 바로 잡기보다는 개선하려고 노력하십시오. ;-)

이것은 첫 번째 답변이므로 모든 면책 조항으로 인해 길이를 용서하십시오 ... 절대적으로 확실하지 않을 때 오만하게 말하고 싶지 않습니다!



5

내 경험상 DELETE, UPDATE, 수많은 단일 INSERT, 트랜잭션 및 전체 텍스트 인덱싱을 수행하지 않는 한 MyISAM이 더 나은 선택이었습니다. BTW, CHECK TABLE은 끔찍합니다. 행 수의 관점에서 테이블이 오래됨에 따라 테이블이 언제 종료되는지 알 수 없습니다.


2
전체 텍스트 인덱싱은 InnoDB가 아닌 MyISAM에서만 가능합니다.
Pixel Elephant

2
@PixelElephant, MySQL 5.6에서 변경되기 시작했습니다. InnoDB에는 전체 텍스트 인덱스 유형이 있지만 지금까지는 IMHO를 프로덕션에 사용할 준비가되지 않았습니다.
Bill Karwin

1
“전체 텍스트 인덱싱은 MynoM에서만 가능하며 InnoDB에서는 불가능합니다.”: MySQL> = 5.6 이후로는 더 이상 사실이 아닙니다. dev.mysql.com/doc/refman/5.6/en/fulltext-search.html을 참조하십시오 .
Hibou57

5

Myisam에 잠금 경합이 있더라도 사용하는 빠른 잠금 획득 체계로 인해 대부분의 시나리오에서 여전히 InnoDb보다 빠릅니다. 나는 Innodb를 여러 번 시도했지만 항상 어떤 이유로 든 MyIsam으로 돌아갑니다. 또한 InnoDB는 대량의 쓰기로드에서 CPU를 많이 사용합니다.


4

모든 응용 프로그램에는 데이터베이스 사용을위한 자체 성능 프로필이 있으며 시간이 지남에 따라 변경 될 가능성이 있습니다.

가장 좋은 방법은 옵션을 테스트하는 것입니다. MyISAM과 InnoDB 간 전환은 쉽지 않으므로 테스트 데이터를로드하고 사이트에 대한 화재 측정기를로드하여 어떤 일이 발생하는지 확인하십시오.


4

MyISAM 및 InnoDB 테이블에 임의의 데이터 삽입을 시도했습니다. 결과는 매우 충격적이었습니다. MyISAM은 InnoDB보다 백만 개의 행을 삽입하는 데 몇 초만 소요되었습니다!


2
트랜잭션을 사용하고 InnoDB 엔진에 대한 자동 커밋을 끄면 동일한 성능을 얻을 수 있습니다.
stanleyxu2005

IDK는 동일한 성능이지만 더 복잡한 응용 프로그램에서 수행하는 작업이며 속도가 빨라집니다.
user965748

1
실험에 대한 정확한 세부 정보를 제공하지 못했습니다 (어떤 구성 설정)? 전에 테이블에 무엇이 있었습니까? 어떤 종류의 데이터? 그리고 아마도 가장 중요한 것은 인서트가 순차적 이었습니까? 평행? 그들의 타이밍은 무엇입니까? CPU 코어는 몇 개입니까? 실? 등
einpoklum

3

myisam은 해당 유형의 워크로드 (높은 동시성 쓰기)에 대한 NOGO입니다 .innodb에 대한 많은 경험이 없습니다. 'mysql을 강제로 실행하지 마십시오. postgres가 동시 쓰기를 더 잘 처리하므로 시도해보십시오.


3

요컨대, 많은 INSERT 및 UPDATE 명령어를 처리 할 수있는 안정적인 데이터베이스가 필요한 작업을 수행하는 경우 InnoDB가 좋습니다.

MyISAM은 테이블 잠금에 대한 단점을 고려하여 쓰기 (INSERT 및 UPDATES)보다는 대부분 많은 읽기 (SELECT) 명령을 수행하는 데이터베이스가 필요한 경우에 좋습니다.

체크 아웃하고 싶을 수도 있습니다.
InnoDB의
장단점 MyISAM의 장단점


2

나는 이것이 인기가 없지만 여기에 간다는 것을 알고있다.

myISAM에는 트랜잭션 및 참조 무결성과 같은 데이터베이스 필수 요소에 대한 지원이 부족하여 종종 결함이 있거나 버그가있는 응용 프로그램이 생성됩니다. DB 엔진에서 지원하지 않는 적절한 데이터베이스 설계 기본 사항을 학습 할 수 없습니다.

데이터베이스 세계에서 참조 무결성 또는 트랜잭션을 사용하지 않는 것은 소프트웨어 세계에서 객체 지향 프로그래밍을 사용하지 않는 것과 같습니다.

InnoDB가 현재 존재합니다. 대신 사용하십시오! myISAM이 모든 레거시 시스템에서 기본값이었던 원래 엔진 임에도 불구하고 MySQL 개발자조차도 최신 버전에서 기본 엔진으로 변경하려고 생각했습니다.

읽기 또는 쓰기 중이거나 성능에 어떤 고려 사항이 있는지는 중요하지 않습니다. myISAM을 사용하면 방금 마주 친 것과 같은 다양한 문제가 발생할 수 있습니다. 데이터베이스 동기화를 수행하는 동시에 다른 사람과 myISAM으로 설정된 테이블에 액세스 한 애플리케이션에 액세스했습니다. 트랜잭션 지원이 부족하고 일반적으로이 엔진의 신뢰성이 떨어지기 때문에 전체 데이터베이스가 손상되어 수동으로 mysql을 다시 시작해야했습니다!

지난 15 년간의 개발 과정에서 많은 데이터베이스와 엔진을 사용했습니다. myISAM은이 기간 동안 다른 데이터베이스에 대해 한 번만 충돌했습니다. 그리고 그것은 일부 개발자가 잘못된 CLR 코드 (공통 언어 런타임-기본적으로 데이터베이스 내부에서 실행되는 C # 코드)를 작성한 Microsoft SQL 데이터베이스 였지만 데이터베이스 엔진의 오류는 아닙니다.

나는 고품질의 고 가용성, 고성능 응용 프로그램이 myISAM을 사용해서는 안되며 견고하거나 안정적이지 않아 좌절없는 경험을 얻을 수 있다고 말하는 다른 답변에 동의 합니다. 자세한 내용은 Bill Karwin의 답변을 참조하십시오.

PS는 myISAM 팬보이들이 공감할 때 좋아하지만이 답변의 어느 부분이 잘못되었는지 말할 수는 없습니다.


5
나는 downvote하지 않았지만 내가 한 경우 절대 사용하지 조언합니다. 단어는 결코 개발자의 어휘에 쓰러져서는 안됩니다.
hubson bropa

1

읽기 / 쓰기 비율에 대해 InnoDB가 더 잘 수행 될 것이라고 생각합니다. 더티 읽기에 문제가 없기 때문에 (만약 여유가 있다면) 슬레이브로 복제하고 모든 읽기를 슬레이브로 옮길 수 있습니다. 또한 한 번에 하나의 레코드가 아니라 대량으로 삽입하는 것을 고려하십시오.


1

거의 새로운 프로젝트를 시작할 때마다 동일한 질문을 Google에 표시하여 새로운 답변이 있는지 확인합니다.

결국 최신 버전으로 업그레이드하고 테스트를 실행합니다.

키 / 값 조회를 수행하려는 테이블이 있습니다. 그게 전부입니다. 해시 키의 값 (0-512 바이트)을 가져와야합니다. 이 DB에는 많은 트랜잭션이 없습니다. 테이블은 때때로 (전체) 업데이트를 얻지 만 트랜잭션은 0입니다.

우리는 여기서 복잡한 시스템에 대해 이야기하지 않고 간단한 조회에 대해 이야기합니다. 그리고 테이블 RAM을 상주시키는 것 이외의 방법으로 성능을 최적화 할 수 있습니다.

또한 다른 데이터베이스 (예 : NoSQL)에서 테스트를 수행하여 이점을 얻을 수있는 곳이 있는지 확인합니다. 내가 찾은 가장 큰 장점은 키 매핑에서 찾을 수 있지만 조회가 진행되는 한 MyISAM은 현재이를 모두 토핑하고 있습니다.

그럼에도 불구하고, MyISAM 테이블을 사용하여 금융 거래를 수행하지는 않지만 간단한 조회를 위해서는 테스트해야합니다. 일반적으로 쿼리 당 초당 2 ~ 5 배입니다.

그것을 테스트, 나는 토론을 환영합니다.


1

인서트가 70 %이고 읽기가 30 %라면 InnoDB 쪽과 비슷합니다.


0

결론 : 많은 양의 데이터를 선택하여 오프라인으로 작업하는 경우 MyISAM은 아마도 더 나은 속도를 제공 할 것입니다.

MyISAM이 InnoDB보다 훨씬 더 효율적인 상황은 다음과 같습니다. 큰 데이터 덤프를 오프라인으로 조작 할 때 (테이블 잠금으로 인해).

예 : VARCHAR 필드를 키로 사용하는 NOAA에서 CSV 파일 (15M 레코드)을 변환했습니다. InnoDB는 많은 양의 메모리를 사용할 수 있어도 영원히 복용하고있었습니다.

이것은 csv의 예입니다 (첫 번째 및 세 번째 필드는 키입니다).

USC00178998,20130101,TMAX,-22,,,7,0700
USC00178998,20130101,TMIN,-117,,,7,0700
USC00178998,20130101,TOBS,-28,,,7,0700
USC00178998,20130101,PRCP,0,T,,7,0700
USC00178998,20130101,SNOW,0,T,,7,

내가해야 할 일은 관측 된 기상 현상의 일괄 오프라인 업데이트를 실행하는 것이므로 데이터를 수신하기 위해 MyISAM 테이블을 사용하고 키에서 JOINS를 실행하여 들어오는 파일을 정리하고 VARCHAR 필드를 INT 키로 대체 할 수 있습니다 (관련 원래 VARCHAR 값이 저장된 외부 테이블).

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