
作者:Eduardo Krieg,来自Percona公司

原文网址:https://www.percona.com/blog/why-mysql-could-be-slow-large-tables
关于译者,姚远:
Oracle ACE(Oracle和MySQL数据库方向)
华为云MVP
《MySQL 8.0运维与优化》的作者
中国唯一一位Oracle高可用大师
拥有包括 Oracle 10g和12c OCM在内的20+数据库相关认证。
曾任IBM公司数据库部门经理
现在一家第三方公司任首席数据库专家,服务2万+客户。
16年前,我们的创始人Peter Zaitsev曾就这个话题写过文章,其中的一些观点至今仍然有效,我们将在这里介绍更多内容。现在的技术已经进化地足够成熟,但仍有一些人认为MySQL仅适用于小型项目,它不能很好地处理大型表。
一些初创公司在早期就采用了MySQL,例如Facebook,Uber,Pinterest等等,这些公司现在是大型而成功的公司,这证明了MySQL可以在大型数据库和高负载的站点上稳定地运行。随着现在磁盘的速度更快,CPU和内存资源更便宜,我们可以更有把握地说MySQL可以以良好的性能处理TB级的数据。例如,在Percona托管服务中,我们有许多客户有TB级数据,并且性能良好。
在这篇博文中,我们将回顾在 MySQL 中更有效地管理大型数据集需要考虑的关键问题。
01
—
主键
02
—
冗余索引
db1 employees> show create table employees\G*************************** 1. row ***************************Table: employeesCreate Table: CREATE TABLE `employees` (`emp_no` int NOT NULL,`birth_date` date NOT NULL,`first_name` varchar(14) NOT NULL,`last_name` varchar(16) NOT NULL,`gender` enum('M','F') NOT NULL,`hire_date` date NOT NULL,PRIMARY KEY (`emp_no`),KEY `idx_last_name` (`last_name`),) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
ALTER TABLE employees ADD INDEX idx_last_name_hire_date (last_name,hire_date);
db1 employees> show create table employees\G*************************** 1. row ***************************Table: employeesCreate Table: CREATE TABLE `employees` (`emp_no` int NOT NULL,`birth_date` date NOT NULL,`first_name` varchar(14) NOT NULL,`last_name` varchar(16) NOT NULL,`gender` enum('M','F') NOT NULL,`hire_date` date NOT NULL,PRIMARY KEY (`emp_no`),KEY `idx_last_name` (`last_name`),KEY `idx_last_name_hire_date` (`last_name`,`hire_date`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
[user1] percona@db1: ~ $ pt-duplicate-key-checker -d employees# ######################################################################### employees.employees# ######################################################################### idx_last_name is a left-prefix of idx_last_name_hire_date# Key definitions:# KEY `idx_last_name` (`last_name`),# KEY `idx_last_name_hire_date` (`last_name`,`hire_date`)# Column types:# `last_name` varchar(16) not null# `hire_date` date not null# To remove this duplicate index, execute:ALTER TABLE `employees`.`employees` DROP INDEX `idx_last_name`;# ######################################################################### Summary of indexes# ######################################################################### Size Duplicate Indexes 350357634# Total Duplicate Indexes 1# Total Indexes 17
03
—
数据类型
db1 test> CREATE TABLE tb1 (id int auto_increment primary key, test_text char(200));Query OK, 0 rows affected (0.11 sec)db1 test> CREATE TABLE tb2 (id int auto_increment primary key, test_text varchar(200));Query OK, 0 rows affected (0.05 sec)db1 test> CREATE TABLE tb3 (id int auto_increment primary key, test_text tinytext);Query OK, 0 rows affected (0.13 sec)db1 test> CREATE TABLE tb4 (id int auto_increment primary key, test_text text);Query OK, 0 rows affected (0.11 sec)
[user1] percona@db1: ~ $ for i in {1..2000}; do for tb in {1..4}; do mysql test -e "INSERT INTO tb$tb (test_text) VALUES ('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse euismod, nulla sit amet rhoncus venenatis, massa dolor lobortis nisi, in.');"; done; done
[user1] percona@db1: ~ $ mysql test -e "select count(*) from tb1; select count(*) from tb2; select count(*) from tb3; select count(*) from tb4;"+----------+| count(*) |+----------+| 2000 |+----------++----------+| count(*) |+----------+| 2000 |+----------++----------+| count(*) |+----------+| 2000 |+----------++----------+| count(*) |+----------+| 2000 |+----------+
[user1] percona@db1: ~ $ sudo ls -lh var/lib/mysql/test/|grep tb-rw-r-----. 1 mysql mysql 592K Dec 30 02:48 tb1.ibd-rw-r-----. 1 mysql mysql 464K Dec 30 02:48 tb2.ibd-rw-r-----. 1 mysql mysql 464K Dec 30 02:48 tb3.ibd-rw-r-----. 1 mysql mysql 464K Dec 30 02:48 tb4.ibd
04
—
压缩
mysql> CREATE TABLE employees_compressed LIKE employees;Query OK, 0 rows affected (0.12 sec)mysql> ALTER TABLE employees_compressed ROW_FORMAT=COMPRESSED;Query OK, 0 rows affected (0.14 sec)Records: 0 Duplicates: 0 Warnings: 0mysql> INSERT INTO employees_compressed SELECT * FROM employees;
[user1] percona@db1: ~ $ sudo ls -lh var/lib/mysql/employees/|grep employees-rw-r-----. 1 mysql mysql 704M Dec 30 02:28 employees.ibd-rw-r-----. 1 mysql mysql 392M Dec 30 17:19 employees_compressed.ibd
05
—
存档数据
一些公司必须将数据保留多年,以保证合规性或业务需求。但是在很多数据仅在短时间内需要访问。例如,为什么要将应用程序会话信息保留多年?
虽然MySQL可以处理大型数据集,但建议仅将有用的数据保留在数据库中,因为这将使数据访问更加高效,并且还有助于节省存储和备份成本。Gaurav有一篇很好的博客文章,《MySQL数据归档与最小中断》
(https://www.percona.com/blog/mysql-data-archival-with-minimal-disruption/)展示了我们如何使用pt-archiver轻松归档旧数据。
06
—
分区(Partitioning)
07
—
分片(Sharding)
ProxySQL
Vitess
08
—
MyRocks
09
—
查询优化
10
—
管理
11
—
结论

近期热文
想快速学好英语吗?来看看一个IT人是如何达到英语专业八级的水平的。
实际上学好Oracle数据库只需要看一本书,让Oracle ACE来告诉你如何学好Oracle数据库?
刚刚上市10天就卖了一千本,京东和当当都卖断了货!
B站上最火的MySQL性能优化课程。
点击“在看”可以阅读我翻译的其他文章👇




