InnoDB는 왜 행 개수를 저장하지 않습니까?


19

InnoDB를 엔진으로 사용 SELECT COUNT(*) FROM mytable하는 테이블에서는 특히 테이블이 커지고 쿼리가 실행되는 동안 일정한 행 삽입 / 삭제가있을 때와 같은 쿼리 가 매우 정확하지 않고 매우 느리다는 것을 알고 있습니다.

내가 이해했듯이 InnoDB는 행 수를 내부 변수에 저장하지 않으므로이 문제의 원인입니다.

내 질문은 : 왜 이렇게됩니까? 그러한 정보를 저장하기가 너무 어려울까요? 많은 상황에서 알아야 할 중요한 정보입니다. 이러한 내부 카운트가 구현되는지 여부를 알 수있는 유일한 어려움은 트랜잭션이 관련된 경우입니다. 트랜잭션이 커밋되지 않은 경우 삽입 된 행을 계산합니까?

추신 : 저는 DB 전문가가 아니며 단순한 취미로 MySQL을 사용하는 사람입니다. 그래서 방금 바보 같은 것을 물었다면 지나치게 비판적이지 마십시오. : D.


6
천천히 요 정확하지 않습니다. 정확한 결과를 제공하기 때문에 속도가 느립니다. 200M 개의 행 테이블과 같은 테이블에 삽입 / 삭제되는 많은 다른 트랜잭션, 초당 많은 행이있을 경우 다른 질문은 "정확한 숫자가 필요합니까?"입니다.
ypercubeᵀᴹ

@ ypercube 나는 phpmyadmin에서 몇 가지 행 수 값을 보았습니다. 또한 "정확하지 않을 수 있습니다"와 같은 의견이 있습니다.
Radu Murzea

1
@RaduMurzea phpMyAdmin 사용자는 알고있는 속도 이유로 InnoDB 테이블의 테이블 수를 계산하는 대체 방법입니다. 이것은 당신이 언급 한 부정확성이 작용하는 곳입니다. 실제 SELECT COUNT(*) FROM ...검색어는 정확합니다. 원하는 경우 속도를 희생하면서 항상 정확한 행 수를 사용하도록 phpMyAdmin을 구성 할 수 있습니다. 더 많은 정보 : stackoverflow.com/questions/11926259/…
DOOManiac

답변:


9

@RemusRusanu에 동의합니다 (대답에 +1).

SELECT COUNT(*) FROM mydb.mytableInnoDB에서는 트랜잭션 스토리지 엔진처럼 작동합니다. MyISAM과 비교하십시오.

MyISAM

경우 mydb.mytableMyISAM 테이블이며, 출시는 SELECT COUNT(*) FROM mydb.mytable;단지 실행과 같다 SELECT table_rows FROM information_schema.table WHERE table_schema = 'mydb' AND table_name = 'mytable';. MyISAM 테이블의 헤더에서 행 수를 빠르게 조회합니다.

InnoDB

mydb.mytableInnoDB 테이블 인 경우 진행중인 작업이 발생합니다. 다음을 관리하는 MVCC가 진행 중입니다.

  • ib_logfile0 / ib_logfile1 (다시 실행 로그)
  • ibdata1
    • 로그 실행 취소
    • 롤백
    • 데이터 사전 변경
  • 버퍼 풀 관리
  • 트랜잭션 격리 (4 가지 유형)
    • 반복 가능한 읽기
    • 커밋 된 읽기
    • 커밋되지 않은 읽기
    • 직렬화 가능

InnoDB에 테이블 수를 요청하면 이러한 불길한 것들을 탐색해야합니다. 실제로, SELECT COUNT(*) from mydb.mytable반복 가능한 읽기만을 카운트 하는지 또는 커밋 된 읽기 및 커밋되지 않은 읽기를 포함 하는지 실제로 알지 못합니다 .

innodb_stats_on_metadata 를 활성화하여 약간의 안정화를 시도 할 수 있습니다.

innodb_stats_on_meta_data 의 MySQL 문서에 따르면

이 변수가 활성화되면 (변수가 생성되기 전의 기본값) InnoDB는 SHOW TABLE STATUS 또는 SHOW INDEX와 같은 메타 데이터 문 또는 INFORMATION_SCHEMA 테이블 TABLES 또는 STATISTICS에 액세스 할 때 통계를 업데이트합니다. (이 업데이트는 ANALYZE TABLE의 경우와 유사합니다.) 비활성화하면 InnoDB는 이러한 작업 중에 통계를 업데이트하지 않습니다. 이 변수를 비활성화하면 테이블 또는 인덱스가 많은 스키마의 액세스 속도가 향상 될 수 있습니다. 또한 InnoDB 테이블과 관련된 쿼리에 대한 실행 계획의 안정성을 향상시킬 수 있습니다.

이 기능을 비활성화하면 EXPLAIN 계획 설정 측면에서보다 안정적인 수를 제공하거나 제공하지 않을 수 있습니다. SELECT COUNT(*) from mydb.mytable좋은 방법, 나쁜 방법 또는 전혀 성능에 영향을 줄 수 있습니다 . 시도하고 참조하십시오!


16

우선 변수에 저장할 '현재 카운트'와 같은 것은 없습니다. 같은 쿼리 SELECT COUNT(*) FROM ...에는 현재 격리 수준과 모든 동시 보류중인 트랜잭션이 적용됩니다. 격리 수준에 따라 쿼리는 커밋되지 않은 트랜잭션을 보류하여 삽입되거나 삭제 된 행을 보거나 볼 수 없습니다. 응답하는 유일한 방법은 현재 트랜잭션에 표시되는 행을 계산하는 것입니다.

계산 중에 시작하거나 끝나는 동시 트랜잭션의 훨씬 더 까다로운 주제는 다루지 않았습니다 . 롤백은 말할 것도없고 ...


1
좋습니다. 격리 수준에 따라 달라집니다. 그러나 여전히 구현할 수 있습니다.
Radu Murzea

@SoboLAN 왜 그런지 말아야 할 이유는 많지 않습니다. 트랜잭션 시작 당 테이블 당 카운트 목록을 유지하여 구현 하시겠습니까 (Oracle의 SCN이 MySQL에있는 것이 무엇이든)? 이러한 수를 관리하는 것은 엄청난 오버 헤드가 될 것입니다. 각각 같은 테이블에서 대량의 INSERT / DELETE를 수행하는 100 또는 1000 개의 동시 세션이있는 데이터베이스를 생각해보십시오. 유지할 수 없습니다.
Philᵀᴹ

이것을 구현하는 것은 매우 어렵습니다. 카운트는 DB에서 유지되어야하고 메타 데이터 어딘가에 있어야한다고 생각 하고 행을 삽입하거나 삭제하는 모든 트랜잭션 에서이 카운트를 유지 해야합니다. 당신은 어떻게 할 메타 데이터를? 롤백을 어떻게 처리 하시겠습니까? 사소한 것이 아닙니다. 결과는 매우 좁은 쿼리 하위 집합에 사용할 수 있습니다.
Remus Rusanu

3
@JackDouglas 재미있는. 과거에 보았던 것 중에서는 COUNT(*)실제로 쿼리가 거의 필요하지 않으며 일반적으로 개발자 경험이 부족하거나 (선택하기 전에 행을 세어보세요!) 나쁜 앱 디자인입니다.
Philᵀᴹ

1
@ 소보 란-아니, 그렇지 않습니다. 사전 정의 된 시간 간격으로 일종의 통계 테이블을 업데이트하는 서비스를 사용하는 것이 훨씬 좋습니다. 큰 데이터베이스와 여러 관리자가로 대부분의 테이블을 쿼리하고 테이블에 SELECT COUNT(*)최적화되지 않은 것을 추가 WHERE한다고 가정하면 몇 명의 사용자가 DB를 무릎으로 가져 와서 몇 가지 유용한 통계 카운터를 사용할 수 있습니다.
NB

0

이론적으로 InnoDB를 사용하여 주어진 테이블에 대해 정확한 행 수를 유지하는 것이 가능하지만 많은 잠금 비용이 들기 때문에 성능에 부정적인 영향을 미칩니다. 또한 격리 수준에 따라 다릅니다.

MyISAM은 이미 테이블 레벨 잠금을 수행하므로 추가 비용이 들지 않습니다.

COUNT (*)를 꽤 많이 사용하지만 테이블에 행 수를 거의 요구하지 않습니다. 나는 일반적으로 WHERE 절이 첨부되어 있습니다. 작은 결과 집합에서 효율적인 색인을 사용하면 충분히 빠릅니다.

개수가 정확하지 않다는 것에 동의하지 않습니다. 카운트는 데이터의 스냅 샷을 나타내며 항상 정확한 것으로 나타났습니다.

요컨대, MySQL은 InnoDB를 위해 이것을 구현할 책임이 있습니다. 각 쿼리 후에 카운트를 저장하고 증가 / 감소 할 수 있습니다. 그러나 더 쉬운 해결책은 아마도 MyISAM으로 전환하는 것입니다.


2
그건 하지 트랜잭션 시스템의 행의 정확한 수를 유지할 수. 활성 트랜잭션과는 다른 (정확한) 행 개수가 많기 때문입니다.
a_horse_with_no_name

5
'여기에 더 쉬운 해결책은 아마도 MyISAM으로 전환하는 것입니다.'에 대해 -1을주었습니다. 행 수를 얻기 위해 MyISAM으로 전환하는 것은 권장하지 않습니다.
데릭 다우니

@a_horse_with_no_name이므로 각 거래에 대해 "올바른"행 개수가 있음에 동의합니다. 나에게 가능한 것 같습니다.
Marcus Adams

1
@ DTest, 나는 "행 수를 얻는 것"이라고 결코 말하지 않았습니다.
Marcus Adams

@a_horse_with_no_name, 그건 옳지 않은 것 같습니다. 확실히 우리는 트랜잭션이 올바르게 커밋 되었을 때만 행 수를 계산 합니까?
Pacerier
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.