iis服务器助手广告广告
返回顶部
首页 > 资讯 > 数据库 >数据库实践丨MySQL多表join分析
  • 805
分享到

数据库实践丨MySQL多表join分析

数据库实践丨MySQL多表join分析 2019-12-04 04:12:42 805人浏览 才女
摘要

摘要:在数据库查询中,往往会需要查询多个表的数据,比如查询会员信息同时查询关于这个会员的订单信息,如果分语句查询的话,效率会很低,就需要用到join关键字来连表查询了。 Join并行 Join并行1. 多表join介绍2.

数据库实践丨MySQL多表join分析

摘要:数据库查询中,往往会需要查询多个表的数据,比如查询会员信息同时查询关于这个会员的订单信息,如果分语句查询的话,效率会很低,就需要用到join关键字来连表查询了。

Join并行

Join并行1. 多表join介绍2. 多表Join的方式不使用Join buffer使用Join buffer3. Join执行流程(老执行器)

1. 多表join介绍

JOIN子句用于根据两个或多个表之间的相关列来组合它们。 例如:

Orders:

Customers:

SELECT Orders.OrderID, Customers.CustomerName, Orders.OrderDate
FROM Orders
INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID;

2. 多表Join的方式

Hash join使用新执行器实现,在这里不做讨论

Mysql支持的都是Nested-Loop Join,以及它的变种。

不使用Join buffer

a) Simple Nested-Loop

对r表的每一行,完整扫描s表,根据r[i]-s[i]组成的行去判断是否满足条件,并返回满足条件的结果给客户端。

mysql> show create table t1;
+-------+----------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                   |
+-------+----------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
 `id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+----------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show create table t3;
+-------+--------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                       |
+-------+--------------------------------------------------------------------------------------------------------------------+
| t3    | CREATE TABLE `t3` (
 `id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+--------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> explain select  * from t1, t3 where t1.id = t3.id;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |   100.00 | NULL        |
|  1 | SIMPLE      | t3    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |    50.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

b) Index Nested-Loop

对r表的每一行,先根据连接条件去查询s表索引,然后回表查到匹配的数据,并返回满足条件的结果给客户端。

mysql> show create table t2;
+-------+---------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                          |
+-------+---------------------------------------------------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
 `id` int(11) NOT NULL,
 KEY `index1` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+---------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> explain select * from t1, t2 where t1.id = t2.id;
+----+-------------+-------+------------+------+---------------+--------+---------+------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key    | key_len | ref        | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+--------+---------+------------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL   | NULL    | NULL       |    2 |   100.00 | NULL        |
|  1 | SIMPLE      | t2    | NULL       | ref  | index1        | index1 | 4       | test.t1.id |    1 |   100.00 | Using index |
+----+-------------+-------+------------+------+---------------+--------+---------+------------+------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)

使用Join buffer

a) Block Nested Loop

 

从r表读取一部分数据到join cache中,当r表数据读完或者join cache满后,做join操作。

JOIN_CACHE_BNL::join_matching_records(){
 do {
   //读取s表的每一行
   qep_tab->table()->file->position(qep_tab->table()->record[0]);
   //针对s的每一行,遍历join buffer
   for(each record in join buffer) {
     get_record();
     rc = generate_full_extensions(get_curr_rec());
     //如果不符合条件,直接返回
     if (rc != NESTED_LOOP_OK) return rc;
   }
 } while(!(error = iterator->Read()))
}

 

mysql> explain select  * from t1, t3 where t1.id = t3.id;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |   100.00 | NULL                                               |
|  1 | SIMPLE      | t3    | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |    50.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

b) Batched Key Access

从r表读取一部分数据到join cache中,s表中记录r表被连接的列的值作为索引,查询所有符合条件的索引,然后将这些符合条件的索引排序,然后统一回表查询记录。

其中,对于每一个cached record,都会有一个key,通过这个key去s表扫描所需的数据。

dsmrr_fill_buffer(){
 while((rowids_buf_cur < rowids_buf_end) &&
       !(res = h2->handler::multi_range_read_next(&range_info))){
   //下压的index条件
   if (h2->mrr_funcs.skip_index_tuple &&
       h2->mrr_funcs.skip_index_tuple(h2->mrr_iter, curr_range->ptr))
     continue;
   memcpy(rowids_buf_cur, h2->ref, h2->ref_length);
 }
 varlen_sort(
     rowids_buf, rowids_buf_cur, elem_size,
     [this](const uchar *a, const uchar *b) { return h->cmp_ref(a, b) < 0; });
}

dsmrr_next(){
 do{
   if (rowids_buf_cur == rowids_buf_last) {
     dsmrr_fill_buffer();
   }
   // first match
   if (h2->mrr_funcs.skip_record &&
       h2->mrr_funcs.skip_record(h2->mrr_iter, (char *)cur_range_info, rowid))
     continue;
   res = h->ha_rnd_pos(table->record[0], rowid);
   break;
 } while(true);
}

JOIN_CACHE_BKA::join_matching_records(){
 while (!(error = file->ha_multi_range_read_next((char **)&rec_ptr))) {
   get_record_by_pos(rec_ptr);
   rc = generate_full_extensions(rec_ptr);
     if (rc != NESTED_LOOP_OK) return rc;
 }
}

 

mysql> show create table t1;
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                    |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
 `f1` int(11) DEFAULT NULL,
 `f2` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+-------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show create table t2;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                   |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
 `f1` int(11) NOT NULL,
 `f2` int(11) NOT NULL,
 `f3` char(200) DEFAULT NULL,
 KEY `f1` (`f1`,`f2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> explain SELECT  t2.f1, t2.f2, t2.f3 FROM t1,t2 WHERE t1.f1=t2.f1 AND t2.f2 BETWEEN t1.f1 and t1.f2 and t2.f2 + 1 >= t1.f1 + 1;
+----+-------------+-------+------------+------+---------------+------+---------+-------------+------+----------+---------------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref         | rows | filtered | Extra                                                         |
+----+-------------+-------+------------+------+---------------+------+---------+-------------+------+----------+---------------------------------------------------------------+
|  1 | SIMPLE      | t1    | NULL       | ALL  | NULL          | NULL | NULL    | NULL        |    3 |   100.00 | Using where                                                   |
|  1 | SIMPLE      | t2    | NULL       | ref  | f1            | f1   | 4       | test1.t1.f1 |    7 |    11.11 | Using index condition; Using join buffer (Batched Key Access) |
+----+-------------+-------+------------+------+---------------+------+---------+-------------+------+----------+---------------------------------------------------------------+
2 rows in set, 1 warning (0.00 sec)

c) Batched Key Access(unique)

与Batched Key Access不同的是,r中的列是s的唯一索引,在r记录写入join cache的时候,会记录一个key的hash table,仅针对不同的key去s表中查询。(疑问,为什么只有unique的时候才能用这种方式?不是unique的话,s表中可能会扫描出多条数据,也可以用这种方式去处理,减少s表的重复扫描)。
JOIN_CACHE_BKA_UNIQUE::join_matching_records(){
 while (!(error = file->ha_multi_range_read_next((char **)&key_chain_ptr))) {
   do(each record in chain){
     get_record_by_pos(rec_ptr);
     rc = generate_full_extensions(rec_ptr);
       if (rc != NESTED_LOOP_OK) return rc;
     }
 }
}

 

mysql> show create table city;
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                       |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| city  | CREATE TABLE `city` (
 `ID` int(11) NOT NULL AUTO_INCREMENT,
 `Name` char(35) NOT NULL DEFAULT "",
 `Country` char(3) NOT NULL DEFAULT "",
 `Population` int(11) NOT NULL DEFAULT "0",
 PRIMARY KEY (`ID`),
 KEY `Population` (`Population`),
 KEY `Country` (`Country`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show create table country;
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                                                                                                                                                                                                                                                      |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| country | CREATE TABLE `country` (
 `Code` char(3) NOT NULL DEFAULT "",
 `Name` char(52) NOT NULL DEFAULT "",
 `SurfaceArea` float(10,2) NOT NULL DEFAULT "0.00",
 `Population` int(11) NOT NULL DEFAULT "0",
 `Capital` int(11) DEFAULT NULL,
 PRIMARY KEY (`Code`),
 UNIQUE KEY `Name` (`Name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+---------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)

mysql> EXPLAIN SELECT city.Name, country.Name FROM city,country WHERE city.country=country.Code AND  country.Name LIKE "L%" AND city.Population > 100000;
+----+-------------+---------+------------+-------+--------------------+---------+---------+--------------------+------+----------+--------------------------------------------------------------+
| id | select_type | table   | partitions | type  | possible_keys      | key     | key_len | ref                | rows | filtered | Extra                                                        |
+----+-------------+---------+------------+-------+--------------------+---------+---------+--------------------+------+----------+--------------------------------------------------------------+
|  1 | SIMPLE      | country | NULL       | index | PRIMARY,Name       | Name    | 208     | NULL               |    1 |   100.00 | Using where; Using index                                     |
|  1 | SIMPLE      | city    | NULL       | ref   | Population,Country | Country | 12      | test1.country.Code |    1 |   100.00 | Using where; Using join buffer (Batched Key Access (unique)) |
+----+-------------+---------+------------+-------+--------------------+---------+---------+--------------------+------+----------+--------------------------------------------------------------+
2 rows in set, 1 warning (0.01 sec)

3. Join执行流程(老执行器)

sub_select <--------------------------------------------+
 | -> iterator::read() // 读一行数据                    |
 | -> evaluate_join_record()  //检查这行数据是否符合条件 |
 | -> next_select() ---+                               |
                       |                               |
sub_select_op  <--------+                               |
 | -> op->put_record() // 前表数据写入join cache        |
   | -> put_record_in_cache()                          |
   | -> join->record()                                 |
     | -> join_matching_records()                      |
       | -> (qep_tab->next_select)(join, qep_tab + 1, 0) // 继续调用next_select
   | -> end_send()

 

点击关注,第一时间了解华为云新鲜技术~

您可能感兴趣的文档:

--结束END--

本文标题: 数据库实践丨MySQL多表join分析

本文链接: https://www.lsjlt.com/news/7730.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • MariaDBSpider数据库分库分表实践记录
    目录分库分表部署 MariaDB 实例Docker 部署虚拟机部署MariaDB 配置检查每个实例配置 Spider远程表基准性能测试加入后端数据库哈希分片根据值范围分片根据列表分片...
    99+
    2024-04-02
  • MySQL 分库分表的项目实践
    目录一、为什么要分库分表二、库表太大产生的问题三、垂直拆分1. 垂直分库2. 垂直分表四、水平分库分表一、为什么要分库分表 数据库架构演变 刚开始多数项目用单机数据库就够了,随着服务...
    99+
    2024-04-02
  • getdata table表格数据join mysql方法的示例分析
    这篇文章主要为大家展示了“getdata table表格数据join mysql方法的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“getdata ta...
    99+
    2024-04-02
  • MySQL分库分表实例分析
    这篇“MySQL分库分表实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“MySQL分库分表实例分析”文章吧。一、为什么...
    99+
    2023-06-30
  • Mysql数据库多实例配置的示例分析
    小编给大家分享一下Mysql数据库多实例配置的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!二进制安装: [root@lufengcentos ~]# mkdi...
    99+
    2024-04-02
  • 数据分析数据库ClickHouse在大数据领域应用实践
    目录一、序言1、应用场景2、学习姿势二、知识储备(一)磁盘IO1、数据量与查询效率(二)性能对比1、磁盘工作机制2、按行(列)存储三、基础知识(一)表结构1、排序2、主键3、默认值(...
    99+
    2024-04-02
  • MySQL数据库约束及表的设计实例分析
    这篇“MySQL数据库约束及表的设计实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“MySQL数据库约束及表的设计实例...
    99+
    2023-07-02
  • 【MySQL数据库】- 多表查询
    🍁博客主页:👉@不会压弯的小飞侠 ✨欢迎关注:👉点赞👍收藏⭐留言✒ ✨系列专栏:👉MySQL数据库专栏 ✨欢迎加入社区: 👉不会压弯的小...
    99+
    2023-08-17
    数据库 mysql sql
  • mysql多表join时候update更新数据的方法
    sql语句:复制代码 代码如下:update item i,resource_library r,resource_review_link l set i.name=CON...
    99+
    2022-11-21
    join update
  • PHP如何实现MySQL数据库分表
    本篇内容介绍了“PHP如何实现MySQL数据库分表”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、MySQL分表的概念MySQL分表是将一...
    99+
    2023-07-06
  • MySQL数据库的多表操作
    目录一、 数据库的多表操作二,操作一对一一对多一、 数据库的多表操作 数据库的多表关系: 一对一一对多多对一多对多 二,操作 一对一 建立数据表person和card,设置perso...
    99+
    2022-11-13
    MySQL数据库 MySQL多表操作
  • Mysql数据库分库分表全面瓦解
    目录1 为什么要分库分表2 垂直拆分(Scale Up 纵向扩展)2.1 垂直分库2.2 垂直分表 3 水平拆分(Scale Out 横向扩展) 3.1 库内分表...
    99+
    2024-04-02
  • 实用数据库开发实践MySQL——数据模型
    目录 第1关 关系模型 关系型数据模型 关系模型基本术语 关系模型的数据操纵与完整性约束 数据操纵 完整性约束 关系模型优缺点 优点 缺点 实验 头歌实验代码 第2关 层次模型 层次型数据模型 层次模型的数据操纵与完整性约束 数据操纵 完整...
    99+
    2023-09-13
    mysql 数据库开发 数据库
  • 怎么在MySQL数据库中实现分表分库操作
    这篇文章将为大家详细讲解有关怎么在MySQL数据库中实现分表分库操作,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。分表分库垂直拆分垂直拆分就是要把表按模块划...
    99+
    2024-04-02
  • Mysql主从复制,读写分离,分表分库策略与实践的示例分析
    本篇文章给大家分享的是有关Mysql主从复制,读写分离,分表分库策略与实践的示例分析,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。一、MySQ...
    99+
    2024-04-02
  • MySQL数据库的示例分析
    这篇文章给大家分享的是有关MySQL数据库的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、数据库概要数据库(Database)是存储与管理数据的软件系统,就像一个存入...
    99+
    2024-04-02
  • 数据分析处理库Pandas——数据透视表
    数据 按指定的行列值显示 求和 按行求和 按列求和 数据 求平均 备注:按性别计算每个等级船票的平均价格。 备注:每个等级船舱中每种性别获救的平均值,也就是获救的比例。 备注:每种性别未成年人获救的平均值...
    99+
    2023-01-31
    数据 透视 Pandas
  • MySQL数据库的性能分析
    本篇内容主要讲解“MySQL数据库的性能分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MySQL数据库的性能分析”吧!  1. MySQL性能优化简介  在...
    99+
    2024-04-02
  • 数据库中如何实现分库分表
    这篇文章将为大家详细讲解有关数据库中如何实现分库分表,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。 分片是解决数据库存储容量限制的直接途径。分片包括垂直分片与水平分片两...
    99+
    2024-04-02
  • MySQL数据库中表查询操作的示例分析
    小编给大家分享一下MySQL数据库中表查询操作的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、单表查询      1...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作