如何提高mysql查询速度

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何提高mysql查询速度相关的知识,希望对你有一定的参考价值。

在已有的 mysql 服务器之上使用 Apache Spark (无需将数据导出到 Spark 或者 Hadoop 平台上),这样至少可以提升 10 倍的查询性能。使用多个 MySQL 服务器(复制或者 Percona XtraDB Cluster)可以让我们在某些查询上得到额外的性能提升。你也可以使用 Spark 的缓存功能来缓存整个 MySQL 查询结果表。

思路很简单:Spark 可以通过 JDBC 读取 MySQL 上的数据,也可以执行 SQL 查询,因此我们可以直接连接到 MySQL 并执行查询。那么为什么速度会快呢?对一些需要运行很长时间的查询(如报表或者BI),由于 Spark 是一个大规模并行系统,因此查询会非常的快。MySQL 只能为每一个查询分配一个 CPU 核来处理,而 Spark 可以使用所有集群节点的所有核。在下面的例子中,我们会在 Spark 中执行 MySQL 查询,这个查询速度比直接在 MySQL 上执行速度要快 5 到 10 倍。

另外,Spark 可以增加“集群”级别的并行机制,在使用 MySQL 复制或者 Percona XtraDB Cluster 的情况下,Spark 可以把查询变成一组更小的查询(有点像使用了分区表时可以在每个分区都执行一个查询),然后在多个 Percona XtraDB Cluster 节点的多个从服务器上并行的执行这些小查询。最后它会使用map/reduce 方式将每个节点返回的结果聚合在一起形成完整的结果。
参考技术A 1、根据查询字段频率设置索引
2、根据SQL优惠器,合理安排数据量少的表的位置
3、如果多表查询合理设置基表的位置
4、利用存储过程

MySQL查询优化——提高速度和效率

【中文标题】MySQL查询优化——提高速度和效率【英文标题】:MySQL query optimization - increase speed and efficiency 【发布时间】:2012-06-30 04:58:18 【问题描述】:

我想在数据库中获取一些电子邮件,并且每封电子邮件都有一个状态。所有可能的状态都存储在一个表中,它们都具有权限(例如显示、编辑、删除等)。这些电子邮件不是通过网站获得权限的用户,而是用户添加的电子邮件列表。

这是表格结构:

电子邮件表格

如果不存在 `email__email` 则创建表( `email_id` int(11) NOT NULL AUTO_INCREMENT, `created` 时间戳 NULL DEFAULT NULL, `updated` 时间戳 NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `user_fk` int(11) 非空, `status_fk` tinyint(2) 非空, `language` enum('fr','en') 整理 utf8_unicode_ci DEFAULT NULL, `email` varchar(255) 整理 utf8_unicode_ci DEFAULT NULL, `firstName` varchar(255) 整理 utf8_unicode_ci DEFAULT NULL, `lastName` varchar(100) 整理 utf8_unicode_ci DEFAULT NULL, `companyName` varchar(255) 整理 utf8_unicode_ci DEFAULT NULL, `gender` enum('f','m') 整理 utf8_unicode_ci DEFAULT NULL, 主键(`email_id`), 唯一键 `user_email` (`user_fk`,`email`), KEY `user_fk` (`user_fk`), KEY `created` (`created`), KEY `status_fk` (`status_fk`) ) 引擎=InnoDB 默认字符集=utf8 排序=utf8_unicode_ci AUTO_INCREMENT=3031492 ;

状态表

如果不存在 `email__status` 则创建表( `status_id` int(11) NOT NULL AUTO_INCREMENT, `name_fr` varchar(50) 整理 utf8_unicode_ci DEFAULT NULL, `name_en` varchar(50) 整理 utf8_unicode_ci DEFAULT NULL, `description_fr` varchar(150) 整理 utf8_unicode_ci DEFAULT NULL, `description_en` varchar(150) 整理 utf8_unicode_ci DEFAULT NULL, `permShow` tinyint(1) NOT NULL DEFAULT '0', `permSend` tinyint(1) NOT NULL DEFAULT '0', `permEdit` tinyint(1) NOT NULL DEFAULT '0', `permDelete` tinyint(1) NOT NULL DEFAULT '0', `permImport` tinyint(1) NOT NULL DEFAULT '0', 主键(`status_id`) ) 引擎=InnoDB 默认字符集=utf8 排序=utf8_unicode_ci AUTO_INCREMENT=7 ;

这是带有 EXPLAIN 的慢查询:

SELECT EE.*, ES.name_fr AS statusName, ES.description_fr AS statusDescription, ES.permShow, ES.permSend, ES.permEdit, ES.permDelete, ES.permImport , (SELECT GROUP_CONCAT(CONVERT(CONCAT(GC.name, '~', GC.group_id), CHAR(255)) SEPARATOR ',') FROM `group` GC INNER JOIN group_email GEC ON GEC.group_fk = GC.group_id WHERE GEC.email_fk = EE.email_id AND GC.deleted = 0) AS 组 FROM `email__email` EE INNER JOIN email__status ES ON EE.status_fk = ES.status_id 其中 1 = 1 和 EE.user_fk = 54 AND ES.permShow = 1 ORDER BY EE.email_id DESC 限制 15 EXTRA ID KEY KEY_LEN POSSIBLE_KEYS REF ROWS SELECT_TYPE TABLE TYPE 使用临时的;使用文件排序 1 user_email 4 user_email,user_fk,status_fk const 180681 PRIMARY EE ref 使用哪里;使用连接缓冲区 1 [空字符串] [空字符串] PRIMARY [空字符串] 6 PRIMARY ES ALL 使用索引 2 email_fk 4 group_email,group_fk,email_fk mailing_dev.EE.email_id 1 DEPENDENT SUBQUERY GEC ref 使用 where 2 PRIMARY 4 PRIMARY mailing_dev.GEC.group_fk 1 DEPENDENT SUBQUERY GC eq_ref

这是一个带有 EXPLAIN 的快速查询:

选择 EE。* , (SELECT GROUP_CONCAT(CONVERT(CONCAT(GC.name, '~', GC.group_id), CHAR(255)) SEPARATOR ',') FROM `group` GC INNER JOIN group_email GEC ON GEC.group_fk = GC.group_id WHERE GEC.email_fk = EE.email_id AND GC.deleted = 0) AS 组 FROM `email__email` EE 其中 1 = 1 和 EE.user_fk = 54 AND EXISTS(从 email__status 中选择 permShow,其中 status_id = EE.status_fk AND permShow = 1) ORDER BY EE.email_id DESC 限制 15 EXTRA ID KEY KEY_LEN POSSIBLE_KEYS REF ROWS SELECT_TYPE TABLE TYPE 使用 where 1 PRIMARY 4 user_email,user_fk [empty string] 270 PRIMARY EE index 使用 where 3 PRIMARY 4 PRIMARY mailing_dev.EE.status_fk 1 DEPENDENT SUBQUERY email__status eq_ref 使用索引 2 email_fk 4 group_email,group_fk,email_fk mailing_dev.EE.email_id 1 DEPENDENT SUBQUERY GEC ref 使用 where 2 PRIMARY 4 PRIMARY mailing_dev.GEC.group_fk 1 DEPENDENT SUBQUERY GC eq_ref

这两个查询之间存在很大差异,但第二个查询没有给我两个需要获取的重要列。我可以像 join 一样做子查询来获取它们,但我仍然不希望每个子查询都有很多......有什么想法可以改进吗?

谢谢

【问题讨论】:

【参考方案1】:

email__email.status_fk 是一个 tinyint,但 email__status.status_id 是一个 int(11)。

这可能会破坏您的 INNER JOIN。更改一种或另一种数据类型,然后重试。

【讨论】:

同时更改为 tinyint(2),然后更改为 int(11) 但没有更改...我运行优化查询来检查基数但仍然没有任何更改。 EXPLAIN 保留在 Using 临时;在 status_fk 上使用文件排序。不过,我会保留您对数据一致性的建议

以上是关于如何提高mysql查询速度的主要内容,如果未能解决你的问题,请参考以下文章

如何提高这个 MySQL 查询的速度?

如何让mysql速度更快的响应?如何提高读取和查询速度

如何提高这个mysql查询的速度

mysql 千万级数据库如何进行多张结构相同的表联合查询?如何优化或设置提高查询速度?

怎么提高数据库查询效率

如何提高ElasticSearch 索引速度