데이터 베이스 MySQL 튜토리얼 大幅提升MySQL中InnoDB的全表扫描速度的方法_MySQL

大幅提升MySQL中InnoDB的全表扫描速度的方法_MySQL

Jun 01, 2016 pm 12:59 PM
innodb mysql

 在 InnoDB中更加快速的全表扫描
 一般来讲,大多数应用查询的时候都会用索引,查找很少的几行数据(主键查找或百行内的查询),但有时候我们需要全表查询。典型的全表扫描就是逻辑备份  (mysqldump) 和 online schema changes( 注:在线上对大表 schema 的操作,也是 facebook 的一个开源项目) (SELECT ... INTO OUTFILE).

 在 Facebook我们用 mysqldump 来备份数据库. 正如你所知MySql提供两种备份方式,提供了物理备份和逻辑备份的命令和工具. 相对物理备份,逻辑备份有一定的优势,例如:

  •     逻辑备份备份数据要小得多. 3x-10x 尺寸差异并不少见。
  •     更容易解析备份数据库. 在物理备份中,在出现严重问题时候,如校验失败。如果我们不能将数据库恢复 ,想知道InnoDB内部数据结构,或者修复损坏是十分困难的。比起物理备份我们更加相逻辑备份。

逻辑备份的主要缺点是数据库的完全备份和完全还原比物理的备份恢复慢得多。

缓慢的完全逻辑备份往往会导致问题.如果数据库中存在很多大小支离破碎的表,它可能需要很长的时间。在 脸书,我们面临 mysqldump 的性能问题,导致我们不能在合理的时间内对一些(基于HDD和Flashcache的)服务器完成完整逻辑备份。我们知道 InnoDB做全表扫描并不高效,因为 InnoDB 实际上并没有顺序读取,在大多情况下是在随机读取。这是一个已知多年的老问题了。我们的数据库存储容量一直在增长,缓慢的全表扫描问题给我们造成了严重的影响,因此,我们决定加强 InnoDB 做顺序读取的速度。最后我们的数据库攻坚工程师团队在InnoDB 中实现了"Logical Readahead"功能。应用"Logical readahead",在通常生产工作负载下,我们全表扫描速比之从前度提高 9 ~ 10 倍。在超负荷生产中,全表扫描速度达到 15 ~ 20 倍的速度甚至更快。

全表扫描在大的、碎片化数据表上的问题
做全表扫描时,InnoDB 会按主键顺序扫描页面和行。这应用于所有的InnoDB 表,包括碎片化的表。如果主键页表没有碎片(存储主键和行的页表),全表扫描是相当快,因为读取顺序接近物理存储顺序。这是类似于读取文件的操作系统命令(dd/cat/etc) 像下面。
 

代码如下:

dd if=/data/mysql/dbname/large_table.ibd of=/dev/null bs=16k iflag=direct


你可能会发现即使在商业HDD服务器上,你可以达到高于比100 MB/s 乘以"驱动器数目"的速度。超过1GB/s并不少见。

不幸的是,在许多情况下主要关键页表存在碎片。例如,如果您需要管理 user_id 和 object_id 映射,主键将会是(user_id,object_id)。插入排序与 user_id并不一致,那么新插入/更新往往导致页拆分。新的拆分页将被分配在远离当前页的位置。这意味着页面将会碎片化。

如果主键页是碎片化的,全表扫描将会变得极其缓慢。图1阐释了这个问题。在InnoDB读取叶子页#3之后,它需要读取页#5230,在那之后还要读页#4。页#5230位置离页#3和页#4很远,所以磁盘读操作顺序开始变得几乎是随机的,而不是连续的。大家都知道HDD上的随机读要比连续读慢得多。一个有效的改进随机读性能的办法是使用SSD。不过SSD每个GB的价钱要比HDD昂贵的多,所以使用SSD通常是不可能的。

2015625104613548.png (480×343)

图 1.全表扫描实际没有连续读

线性预读取真的有意义吗?
InnoDB支持预读取特性,称作“线性预读取”( Linear Read Ahead)。拥有线性预读取,如果N个page可以顺序访问(N可以通过innodb_read_ahead_threshold参数进行配置,默认为56),InnoDB可以一次读取一个extent(64个连续的page,如果不压缩每个page为1MB)。但是,实际来说这么做的意义不大。一个extent(64个page)非常小。对于一个支离破碎的较大的数据库表来说,下一个page不一定在同一个extent当中。上面图1就是一个很好的例子。读取page#3之后,InnoDB需要读取page#5230。page#3和page#5230并不在同一个extent当中,所以线性预读取技术在这里用处不大。这对于大表来说是非常常见的情况,所以这也解释了线性预读取技术为什么不能有效改善全表扫描的性能。
 
物理预读取
正如上面描述的,全表扫描速度较慢的主要原因是InnoDB主要进行随机读取。为了加速全表扫描,需要使InnoDB进行顺序读取。我想到的第一个方法就是创建一个UDF(user defined function)顺序的读取ibd文件(InnoDB的数据文件)。UDF执行完成后,ibd文件的page应当保存在InnoDB的缓存池当中,所以在进行全表扫描时无需再进行随机读取。下面是一个示例用法:
 

mysql> SELECT buf_warmup ("db1", "large_table"); /* loading into buf pool */
mysql> SELECT * FROM large_application_table; /* in-memory select */
로그인 후 복사

buf_warmup() 是一个用户自定义函数,用来读取数据库“db1"的表”large_table"的整个ibd文件。该函数需要花费时间将ibd文件从硬盘读取,但因为是顺序读取的,所以比随机读取要快的多。在我的测试当中,比普通的线性预读取快差不多5倍左右。

这证明ibd文件的顺序读取能够有效的改善吞吐率,但也存在一些缺点:

  •     如果table的大小超过InnoDB缓存池的大小,这种方法就不能工作
  •     在全表扫描过程中,读取整个的ibd文件就意味着不但需要读取primary key page还需要读取二级索引page以及一些其他不需要的page,并将其保存在缓存池,尽管只有primary key page是实际需要的。如果拥有大量的二级索引,这种方法就不能有效的工作
  •     应用需要做出一定的修改以便调用UDF

这看起来是一个足够好的解决方案,但我们的数据库设计团队想出了一个更好的解决方法叫做“逻辑预读取”(Logical Read Ahead),所以我们并不选择UDF的方法。

逻辑预读取
逻辑预读取(LRA)的工作流程如下:

  •     读取主键的一些分支page
  •     计算叶子page的数量
  •     以page number的顺序(大多数是顺序磁盘读取)依次读取一些(通过配置控制数量的多少)叶子page
  •     以主键的顺序读取行

整个流程如图2所示:

2015625104633538.png (480×262)

Fig 2: Logical Read Ahead


逻辑预读取解决了物理预读取所存在的问题。LRA使InnoDB仅读取主键page(不需要读取二级索引页面),并且每一次预读取页面的数量是可以控制的。除此之外,LRA对SQL语法不需要做任何修改。

为了使LRA工作,我们需要增加两个session变量。一个是"innodb_lra_size",用来控制预读取叶子页面(page)大小。另外一个是"innodb_lra_sleep",用来控制每一次预读取之间休眠多长时间。我们用512MB~4096MB的大小以及50毫秒的休眠时间来进行测试,到目前为止我们还没有遇到任何严重问题(例如崩溃/阻塞/不一致等)。这些session变量仅在需要进行全表的时候进行设置。在我们的应用中,mysqldump以及其他一些辅助脚本启用了逻辑预读取。

一次提交多个async I/O请求

我们注意到,另外一个导致性能问题的原因是InnoDB 每次i/o仅读取一个页面,即使开启了预读取技术。每次仅读取16KB对于顺序读取来说实在是太小了,效率相比大的读取单元要低很多。

在版本5.6中,InnoDB默认使用Linux本地I/O。如果一次提交多个连续的16KB读请求,Linux在内部会将这些请求合并,读操作能够更有效的执行。不幸的是,InnoDB一次只会提交一个页面的i/o请求。我提交了一个bug report#68659.正如bug report中所写,在一个当代的HDD RAID 1+0环境中,如果我一次性提交64个连续的页面读取请求,我可以获得超过1000MB/s的硬盘读取速度;如果每次只提交一个页面读取请求,我们仅可以获得160MB/s的硬盘读取速度。

为了使LRA在我们的应用环境中更好的工作,我们修正了这个问题。在我们的MySQl中,InnoDB在调用io_submit()之前会提交多个页面i/o请求。

基准测试
在所有的测试中,我们使用的都是生产环境下的数据库表(分页的表)。

1. 纯HDD环境全表扫描 (基础的基准测试, 没有其他的工作负载)

2015625104655569.jpg (411×92)

2. Online schema change under heavy workload

2015625104718902.jpg (337×63)

* dump time only, not counting data loading time
 源码
 我们做出的所有增强修改都可以在GitHub上获取。

  •  - 逻辑预读取实现 : diff
  •  - 一次提交多个i/o请求:diff
  •  - 在mydqldump中启用逻辑预读取 :diff


结论

对于全表扫描来说InnoDB的工作效率不高,所以我们对它做了一定的修改。我在两方面进行了改进,一是实现了逻辑预读取;一是实现了一次提交多个async read i/o请求。对于我们生产环境中的数据库表来说,我们获得了8-18倍的性能提高,这对于减少备份时间、模式修改时间等来说是非常有用的。我希望这些特性能够在InnoDB中获得Oracle官方支持,至少是主要的MySQL分支。

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

phpmyadmin을 여는 방법 phpmyadmin을 여는 방법 Apr 10, 2025 pm 10:51 PM

다음 단계를 통해 phpmyadmin을 열 수 있습니다. 1. 웹 사이트 제어판에 로그인; 2. phpmyadmin 아이콘을 찾고 클릭하십시오. 3. MySQL 자격 증명을 입력하십시오. 4. "로그인"을 클릭하십시오.

MySQL : 세계에서 가장 인기있는 데이터베이스 소개 MySQL : 세계에서 가장 인기있는 데이터베이스 소개 Apr 12, 2025 am 12:18 AM

MySQL은 오픈 소스 관계형 데이터베이스 관리 시스템으로, 주로 데이터를 신속하고 안정적으로 저장하고 검색하는 데 사용됩니다. 작업 원칙에는 클라이언트 요청, 쿼리 해상도, 쿼리 실행 및 반환 결과가 포함됩니다. 사용의 예로는 테이블 작성, 데이터 삽입 및 쿼리 및 조인 작업과 같은 고급 기능이 포함됩니다. 일반적인 오류에는 SQL 구문, 데이터 유형 및 권한이 포함되며 최적화 제안에는 인덱스 사용, 최적화 된 쿼리 및 테이블 분할이 포함됩니다.

단일 스레드 레 디스를 사용하는 방법 단일 스레드 레 디스를 사용하는 방법 Apr 10, 2025 pm 07:12 PM

Redis는 단일 스레드 아키텍처를 사용하여 고성능, 단순성 및 일관성을 제공합니다. 동시성을 향상시키기 위해 I/O 멀티플렉싱, 이벤트 루프, 비 블로킹 I/O 및 공유 메모리를 사용하지만 동시성 제한 제한, 단일 고장 지점 및 쓰기 집약적 인 워크로드에 부적합한 제한이 있습니다.

MySQL을 사용하는 이유는 무엇입니까? 혜택과 장점 MySQL을 사용하는 이유는 무엇입니까? 혜택과 장점 Apr 12, 2025 am 12:17 AM

MySQL은 성능, 신뢰성, 사용 편의성 및 커뮤니티 지원을 위해 선택됩니다. 1.MYSQL은 효율적인 데이터 저장 및 검색 기능을 제공하여 여러 데이터 유형 및 고급 쿼리 작업을 지원합니다. 2. 고객-서버 아키텍처 및 다중 스토리지 엔진을 채택하여 트랜잭션 및 쿼리 최적화를 지원합니다. 3. 사용하기 쉽고 다양한 운영 체제 및 프로그래밍 언어를 지원합니다. 4. 강력한 지역 사회 지원을 받고 풍부한 자원과 솔루션을 제공합니다.

MySQL의 장소 : 데이터베이스 및 프로그래밍 MySQL의 장소 : 데이터베이스 및 프로그래밍 Apr 13, 2025 am 12:18 AM

데이터베이스 및 프로그래밍에서 MySQL의 위치는 매우 중요합니다. 다양한 응용 프로그램 시나리오에서 널리 사용되는 오픈 소스 관계형 데이터베이스 관리 시스템입니다. 1) MySQL은 웹, 모바일 및 엔터프라이즈 레벨 시스템을 지원하는 효율적인 데이터 저장, 조직 및 검색 기능을 제공합니다. 2) 클라이언트 서버 아키텍처를 사용하고 여러 스토리지 엔진 및 인덱스 최적화를 지원합니다. 3) 기본 사용에는 테이블 작성 및 데이터 삽입이 포함되며 고급 사용에는 다중 테이블 조인 및 복잡한 쿼리가 포함됩니다. 4) SQL 구문 오류 및 성능 문제와 같은 자주 묻는 질문은 설명 명령 및 느린 쿼리 로그를 통해 디버깅 할 수 있습니다. 5) 성능 최적화 방법에는 인덱스의 합리적인 사용, 최적화 된 쿼리 및 캐시 사용이 포함됩니다. 모범 사례에는 거래 사용 및 준비된 체계가 포함됩니다

Redis Exporter 서비스로 Redis 액 적을 모니터링하십시오 Redis Exporter 서비스로 Redis 액 적을 모니터링하십시오 Apr 10, 2025 pm 01:36 PM

Redis 데이터베이스의 효과적인 모니터링은 최적의 성능을 유지하고 잠재적 인 병목 현상을 식별하며 전반적인 시스템 신뢰성을 보장하는 데 중요합니다. Redis Exporter Service는 Prometheus를 사용하여 Redis 데이터베이스를 모니터링하도록 설계된 강력한 유틸리티입니다. 이 튜토리얼은 Redis Exporter Service의 전체 설정 및 구성을 안내하여 모니터링 솔루션을 원활하게 구축 할 수 있도록합니다. 이 자습서를 연구하면 완전히 작동하는 모니터링 설정을 달성 할 수 있습니다.

Apache의 데이터베이스에 연결하는 방법 Apache의 데이터베이스에 연결하는 방법 Apr 13, 2025 pm 01:03 PM

Apache는 데이터베이스에 연결하여 다음 단계가 필요합니다. 데이터베이스 드라이버 설치. 연결 풀을 만들려면 Web.xml 파일을 구성하십시오. JDBC 데이터 소스를 작성하고 연결 설정을 지정하십시오. JDBC API를 사용하여 Connections, 명세서 작성, 매개 변수 바인딩, 쿼리 또는 업데이트 실행 및 처리를 포함하여 Java 코드의 데이터베이스에 액세스하십시오.

phpmyadmin 연결 MySQL phpmyadmin 연결 MySQL Apr 10, 2025 pm 10:57 PM

phpmyadmin을 사용하여 MySQL에 연결하는 방법? phpmyadmin에 액세스하기위한 URL은 일반적으로 http : // localhost/phpmyadmin 또는 http : // [서버 IP 주소]/phpmyadmin입니다. MySQL 사용자 이름 및 비밀번호를 입력하십시오. 연결하려는 데이터베이스를 선택하십시오. "연결"버튼을 클릭하여 연결을 설정하십시오.

See all articles