SQL优化系列-快速学会分析SQL执行效率(下)

news2025/4/8 11:56:52

1 show profile 分析慢查询

有时需要确定 SQL 到底慢在哪个环节,此时 explain 可能不好确定。在 MySQL 数据库中,通过 profile,能够更清楚地了解 SQL 执行过程的资源使用情况,能让我们知道到底慢在哪个环节。

知识扩展:可以通过配置参数 profiling = 1 来启用 SQL 分析。该参数可以在全局和 session 级别来设置。对于全局级别则作用于整个MySQL 实例,而 session 级别仅影响当前 session 。该参数开启后,后续执行的 SQL 语句都将记录其资源开销,如 IO、上下文切换、CPU、Memory等等。根据这些开销进一步分析当前 SQL 从而进行优化与调整。

下面我们来讲一下如何使用 profile 分析慢查询,大致步骤是:确定这个 MySQL 版本是否支持 profile;确定 profile 是否关闭;开启 profile;执行 SQL;查看执行完 SQL 的 query id;通过 query id 查看 SQL 的每个状态及耗时时间。

1.1 确定是否支持 profile

我们进行第一步,用下面命令来判断当前 MySQL 是否支持 profile:

mysql> select @@have_profiling;

+------------------+
| @@have_profiling |
+------------------+
| YES              |
+------------------+

1 row in set, 1 warning (0.00 sec)

从上面结果中可以看出是YES,表示支持profile的。

1.2 查看 profiling 是否关闭的

进行第二步,用下面命令判断 profiling 参数是否关闭(默认 profiling 是关闭的):

mysql> select @@profiling;

+-------------+
| @@profiling |
+-------------+
|           0 |
+-------------+

1 row in set, 1 warning (0.00 sec)

结果显示为 0,表示 profiling 参数状态是关闭的。

1.3 通过 set 开启 profile

mysql> set profiling=1;

Query OK, 0 rows affected, 1 warning (0.00 sec)

Tips:set 时没加 global,只对当前 session 有效。

1.4 执行 SQL 语句

mysql> select * from t1 where b=1000;

1.5 确定 SQL 的 query id

通过 show profiles 语句确定执行过的 SQL 的 query id:

mysql> show profiles;
+----------+------------+-------------------------------+
| Query_ID | Duration   | Query                         |
+----------+------------+-------------------------------+
|        1 | 0.00063825 | select * from t1 where b=1000 |
+----------+------------+-------------------------------+
1 row in set, 1 warning (0.00 sec)

1.6 查询 SQL 执行详情

通过 show profile for query 可看到执行过的 SQL 每个状态和消耗时间:

mysql> show profile for query 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000115 |
| checking permissions | 0.000013 |
| Opening tables       | 0.000027 |
| init                 | 0.000035 |
| System lock          | 0.000017 |
| optimizing           | 0.000016 |
| statistics           | 0.000025 |
| preparing            | 0.000020 |
| executing            | 0.000006 |
| Sending data         | 0.000294 |
| end                  | 0.000009 |
| query end            | 0.000012 |
| closing tables       | 0.000011 |
| freeing items        | 0.000024 |
| cleaning up          | 0.000016 |
+----------------------+----------+
15 rows in set, 1 warning (0.00 sec)

通过以上结果,可以确定 SQL 执行过程具体在哪个过程耗时比较久,从而更好地进行 SQL 优化与调整。

2 trace 分析 SQL 优化器

从前面学到了 explain 可以查看 SQL 执行计划,但是无法知道它为什么做这个决策,如果想确定多种索引方案之间是如何选择的或者排序时选择的是哪种排序模式,有什么好的办法吗?

从 MySQL 5.6 开始,可以使用 trace 查看优化器如何选择执行计划。

通过trace,能够进一步了解为什么优化器选择A执行计划而不是选择B执行计划,或者知道某个排序使用的排序模式,帮助我们更好地理解优化器行为。

如果需要使用,先开启 trace,设置格式为 JSON,再执行需要分析的 SQL,最后查看 trace 分析结果(在 information_schema.OPTIMIZER_TRACE 中)。

开启该功能,会对 MySQL 性能有所影响,因此只建议分析问题时临时开启。

下面一起来看下 trace 的使用方法。使用讲解 explain 时创建的表t1做实验。

首先构造如下 SQL (表示取出表 t1 中 a 的值大于 900 并且 b 的值大于 910 的数据,然后按照 a 字段排序):

select * from t1 where a >900 and b > 910 order  by a;

我们首先用 explain 分析下执行计划:

通过上面执行计划中 key 这个字段可以看出,该语句使用的是 b 字段的索引 idx_b。实际表 t1 中,a、b 两个字段都有索引,为什么条件中有这两个索引字段却偏偏选了 b 字段的索引呢?这时就可以使用 trace 进行分析。大致步骤如下:

mysql> set session optimizer_trace="enabled=on",end_markers_in_json=on;
/* optimizer_trace="enabled=on" 表示开启 trace;end_markers_in_json=on 表示 JSON 输出开启结束标记 */
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1 where a >900 and b > 910 order  by a;
+------+------+------+
| id   | a    | b    |
+------+------+------+
|    1 |    1 |    1 |
|    2 |    2 |    2 |

......

| 1000 | 1000 | 1000 |
+------+------+------+
1000 rows in set (0.00 sec)

mysql> SELECT * FROM information_schema.OPTIMIZER_TRACE\G
*************************** 1. row ***************************
QUERY: select * from t1 where a >900 and b > 910 order  by a    --SQL语句
TRACE: {
  "steps": [
    {
      "join_preparation": {				--SQL准备阶段
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `t1`.`id` AS `id`,`t1`.`a` AS `a`,`t1`.`b` AS `b`,`t1`.`create_time` AS `create_time`,`t1`.`update_time` AS `update_time` from `t1` where ((`t1`.`a` > 900) and (`t1`.`b` > 910)) order by `t1`.`a`"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": {			--SQL优化阶段
        "select#": 1,
        "steps": [
          {
            "condition_processing": {    --条件处理
              "condition": "WHERE",
              "original_condition": "((`t1`.`a` > 900) and (`t1`.`b` > 910))",        --原始条件
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "((`t1`.`a` > 900) and (`t1`.`b` > 910))" 		--等值传递转换
                },
                {
                  "transformation": "constant_propagation",
                  "resulting_condition": "((`t1`.`a` > 900) and (`t1`.`b` > 910))"       --常量传递转换
                },
                {
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "((`t1`.`a` > 900) and (`t1`.`b` > 910))"        --去除没有的条件后的结构
                }
              ] /* steps */
            } /* condition_processing */
          },
          {
            "substitute_generated_columns": {
            } /* substitute_generated_columns */   --替换虚拟生成列
          },
          {
            "table_dependencies": [		--表依赖详情
              {
                "table": "`t1`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ] /* depends_on_map_bits */
              }
            ] /* table_dependencies */
          },
          {
            "ref_optimizer_key_uses": [
            ] /* ref_optimizer_key_uses */
          },
          {
            "rows_estimation": [	--预估表的访问成本
              {
                "table": "`t1`",
                "range_analysis": {
                  "table_scan": {
                    "rows": 1000,       --扫描行数
                    "cost": 207.1       --成本
                  } /* table_scan */,
                  "potential_range_indexes": [    --分析可能使用的索引
                    {
                      "index": "PRIMARY",
                      "usable": false,       --为false,说明主键索引不可用
                      "cause": "not_applicable"
                    },
                    {
                      "index": "idx_a",      --可能使用索引idx_a
                      "usable": true,
                      "key_parts": [
                        "a",
                        "id"
                      ] /* key_parts */
                    },
                    {
                      "index": "idx_b",      --可能使用索引idx_b
                      "usable": true,
                      "key_parts": [
                        "b",
                        "id"
                      ] /* key_parts */
                    }
                  ] /* potential_range_indexes */,
                  "setup_range_conditions": [
                  ] /* setup_range_conditions */,
                  "group_index_range": {
                    "chosen": false,
                    "cause": "not_group_by_or_distinct"
                  } /* group_index_range */,
                  "analyzing_range_alternatives": { --分析各索引的成本
                    "range_scan_alternatives": [
                      {
                        "index": "idx_a",	--使用索引idx_a的成本
                        "ranges": [
                          "900 < a"			--使用索引idx_a的范围
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true, --是否使用index dive(详细描述请看下方的知识扩展)
                        "rowid_ordered": false, --使用该索引获取的记录是否按照主键排序
                        "using_mrr": false,  	--是否使用mrr
                        "index_only": false,    --是否使用覆盖索引
                        "rows": 100,            --使用该索引获取的记录数
                        "cost": 121.01,         --使用该索引的成本
                        "chosen": true          --可能选择该索引
                      },
                      {
                        "index": "idx_b",       --使用索引idx_b的成本
                        "ranges": [
                          "910 < b"
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,
                        "using_mrr": false,
                        "index_only": false,
                        "rows": 90,
                        "cost": 109.01,
                        "chosen": true             --也可能选择该索引
                      }
                    ] /* range_scan_alternatives */,
                    "analyzing_roworder_intersect": { --分析使用索引合并的成本
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    } /* analyzing_roworder_intersect */
                  } /* analyzing_range_alternatives */,
                  "chosen_range_access_summary": {  --确认最优方法
                    "range_access_plan": {
                      "type": "range_scan",
                      "index": "idx_b",
                      "rows": 90,
                      "ranges": [
                        "910 < b"
                      ] /* ranges */
                    } /* range_access_plan */,
                    "rows_for_plan": 90,
                    "cost_for_plan": 109.01,
                    "chosen": true
                  } /* chosen_range_access_summary */
                } /* range_analysis */
              }
            ] /* rows_estimation */
          },
          {
            "considered_execution_plans": [  --考虑的执行计划
              {
                "plan_prefix": [
                ] /* plan_prefix */,
                "table": "`t1`",
                "best_access_path": {          --最优的访问路径
                  "considered_access_paths": [ --决定的访问路径
                    {
                      "rows_to_scan": 90,      --扫描的行数
                      "access_type": "range",  --访问类型:为range
                      "range_details": {
                        "used_index": "idx_b"  --使用的索引为:idx_b
                      } /* range_details */,
                      "resulting_rows": 90,    --结果行数
                      "cost": 127.01,          --成本
                      "chosen": true,		   --确定选择
                      "use_tmp_table": true
                    }
                  ] /* considered_access_paths */
                } /* best_access_path */,
                "condition_filtering_pct": 100,
                "rows_for_plan": 90,
                "cost_for_plan": 127.01,
                "sort_cost": 90,
                "new_cost_for_plan": 217.01,
                "chosen": true
              }
            ] /* considered_execution_plans */
          },
          {
            "attaching_conditions_to_tables": {  --尝试添加一些其他的查询条件
              "original_condition": "((`t1`.`a` > 900) and (`t1`.`b` > 910))",
              "attached_conditions_computation": [
              ] /* attached_conditions_computation */,
              "attached_conditions_summary": [
                {
                  "table": "`t1`",
                  "attached": "((`t1`.`a` > 900) and (`t1`.`b` > 910))"
                }
              ] /* attached_conditions_summary */
            } /* attaching_conditions_to_tables */
          },
          {
            "clause_processing": {
              "clause": "ORDER BY",
              "original_clause": "`t1`.`a`",
              "items": [
                {
                  "item": "`t1`.`a`"
                }
              ] /* items */,
              "resulting_clause_is_simple": true,
              "resulting_clause": "`t1`.`a`"
            } /* clause_processing */
          },
          {
            "reconsidering_access_paths_for_index_ordering": {
              "clause": "ORDER BY",
              "index_order_summary": {
                "table": "`t1`",
                "index_provides_order": false,
                "order_direction": "undefined",
                "index": "idx_b",
                "plan_changed": false
              } /* index_order_summary */
            } /* reconsidering_access_paths_for_index_ordering */
          },
          {
            "refine_plan": [          --改进的执行计划
              {
                "table": "`t1`",
                "pushed_index_condition": "(`t1`.`b` > 910)",
                "table_condition_attached": "(`t1`.`a` > 900)"
              }
            ] /* refine_plan */
          }
        ] /* steps */
      } /* join_optimization */
    },
    {
      "join_execution": {             --SQL执行阶段
        "select#": 1,
        "steps": [
          {
            "filesort_information": [
              {
                "direction": "asc",
                "table": "`t1`",
                "field": "a"
              }
            ] /* filesort_information */,
            "filesort_priority_queue_optimization": {
              "usable": false,             --未使用优先队列优化排序
              "cause": "not applicable (no LIMIT)"     --未使用优先队列排序的原因是没有limit
            } /* filesort_priority_queue_optimization */,
            "filesort_execution": [
            ] /* filesort_execution */,
            "filesort_summary": {           --排序详情
              "rows": 90,
              "examined_rows": 90,          --参与排序的行数
              "number_of_tmp_files": 0,     --排序过程中使用的临时文件数
              "sort_buffer_size": 115056,
              "sort_mode": "<sort_key, additional_fields>"   --排序模式(详解请看下方知识扩展)
            } /* filesort_summary */
          }
        ] /* steps */
      } /* join_execution */
    }
  ] /* steps */
}
MISSING_BYTES_BEYOND_MAX_MEM_SIZE: 0	--该字段表示分析过程丢弃的文本字节大小,本例为0,说明没丢弃任何文本
          INSUFFICIENT_PRIVILEGES: 0    --查看trace的权限是否不足,0表示有权限查看trace详情
1 row in set (0.00 sec)
------------------------------------------------
------------------------------------------------


mysql> set session optimizer_trace="enabled=off";
/* 及时关闭trace */

这里对上方的执行字段详细描述一下:

TRACE 字段中整个文本大致分为三个过程。

  • 准备阶段:对应文本中的 join_preparation
  • 优化阶段:对应文本中的 join_optimization
  • 执行阶段:对应文本中的 join_execution

使用时,重点关注优化阶段和执行阶段。

由此例可以看出:

  • 在 trace 结果的 analyzing_range_alternatives 这一项可以看到:使用索引 idx_a 的成本为 121.01,使用索引 idx_b 的成本为 109.01,显然使用索引 idx_b 的成本要低些,因此优化器选择了 idx_b 索引;
  • 在 trace 结果的 filesort_summary 这一项可以看到:排序模式为<sort_key, additional_fields>,表示使用的是单路排序,即一次性取出满足条件行的所有字段,然后在 sort buffer 中进行排序。

知识扩展:

知识点一:MySQL 常见排序模式:

  • < sort_key, rowid >双路排序(又叫回表排序模式):是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行 ID,然后在 sort buffer 中进行排序,排序完后需要再次取回其它需要的字段;
  • < sort_key, additional_fields >单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序;
  • < sort_key, packed_additional_fields >打包数据排序模式:将 char 和 varchar 字段存到 sort buffer 中时,更加紧缩。

三种排序模式比较:

第二种模式相对第一种模式,避免了二次回表,可以理解为用空间换时间。由于 sort buffer 有限,如果需要查询的数据比较大的话,会增加磁盘排序时间,效率可能比第一种方式更低。

MySQL 提供了一个参数:max_length_for_sort_data,当“排序的键值对大小” > max_length_for_sort_data 时,MySQL 认为磁盘外部排序的 IO 效率不如回表的效率,会选择第一种排序模式;否则,会选择第二种模式。

第三种模式主要解决变长字符数据存储空间浪费的问题。

知识点二:优化器在估计符合条件的行数时有两个选择:

  • index diver:dive 到 index 中利用索引完成元组数的估算;特点是速度慢,但可以得到精确的值;
  • index statistics:使用索引的统计数值,进行估算;特点是速度快,但是值不一定准确。

3 总结

今天我们分享了 show profile 和 trace 的使用方法,我们来对比一下三种分析 SQL 方法的特点:

  • explain:获取 MySQL 中 SQL 语句的执行计划,比如语句是否使用了关联查询、是否使用了索引、扫描行数等;
  • profile:可以清楚了解到SQL到底慢在哪个环节;
  • trace:查看优化器如何选择执行计划,获取每个可能的索引选择的代价。

三种方法各有其适用场景

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1796217.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Wireshark 如何查找包含特定数据的数据帧

1、查找包含特定 string 的数据帧 使用如下指令&#xff1a; 双引号中所要查找的字符串 frame contains "xxx" 查找字符串 “heartbeat” 示例&#xff1a; 2、查找包含特定16进制的数据帧 使用如下指令&#xff1a; TCP&#xff1a;在TCP流中查找 tcp contai…

汽车分销商文件流转优化:实现稳定高效的文件分发处理

在汽车圈里&#xff0c;分销商可是个不可或缺的角色。他们既要跟汽车厂家紧紧绑在一起&#xff0c;还得跟下游的销售渠道或者直接跟消费者打成一片&#xff0c;文件来回传递那是家常便饭。 这文件发放的速度快不快&#xff0c;安不安全&#xff0c;直接影响到分销商做事的效率…

容器(Docker)安装

centos安装Docker sudo yum remove docker* sudo yum install -y yum-utils#配置docker的yum地址 sudo yum-config-manager \ --add-repo \ http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo#安装指定版本 - 可以根据实际安装版本 sudo yum install -y docke…

Centos 报错 One of the configured repositories failed

目录预览 一、问题描述二、原因分析三、解决方案四、参考链接 一、问题描述 使用yum update更新命令就出现下面问题&#xff0c;系统是刚安装的&#xff0c;然后修改了一下IP变成手动。&#xff08;排查问题前&#xff0c;先回顾自己做了哪些操作&#xff0c;方便进一步排错&a…

策略模式的理解和运用

在之前的小游戏项目中&#xff0c;处理websocket长连接请求的时候&#xff0c;需要根据传递数据包的不同类型&#xff0c;进行不同的处理。为了实现这个场景&#xff0c;比较简单的方法就是使用if-else或者switch-case语句&#xff0c;根据条件进行判断。但是这导致了项目代码复…

梦幻西游外网架设教程-端游篇

《梦幻西游》是一款由中国网易公司自行开发并营运的网络国产游戏。游戏以著名的章回小说《西游记》故事为背景&#xff0c;透过Q版的人物&#xff0c;试图营造出浪漫的网络游戏风格。 《梦幻西游》拥有注册用户超过3.1亿&#xff0c;一共开设收费服务器达472组&#xff0c;最高…

Sigmoid图像

import matplotlib.pyplot as plt import numpy as npdef sigmoid(x):# 直接返回sigmoid函数return 1. / (1. np.exp((0.7 -(x))/0.075))def plot_sigmoid():# param:起点&#xff0c;终点&#xff0c;间距x np.arange(0, 1, 1 / 16000)y sigmoid(x)plt.plot(x, y)plt.show…

【WP】猿人学_19_乌拉乌拉乌拉

https://match.yuanrenxue.cn/match/19 发包测试 经过发包测试&#xff0c;并没有携带加密参数&#xff0c;但是使用python无法复现&#xff0c;requests&#xff0c;httpx以及异步都不行&#xff0c;网上搜索了一下&#xff0c;这是使用了JA3指纹。可能是我做的时间比较晚&…

【iOS】UI学习——导航控制器、分栏控制器

UI学习&#xff08;三&#xff09; 导航控制器导航控制器基础导航控制器切换导航栏和工具栏 分栏控制器分栏控制器基础分栏控制器高级 导航控制器 导航控制器负责控制导航栏&#xff08;navigationBar&#xff09;&#xff0c;导航栏上的按钮叫UINavigationItem&#xff08;导航…

【论文阅读】SELF-RAG,让模型决策和反思检索

关于LLM何时使用RAG的问题&#xff0c;原本是阅读了关于ADAPT-LLM模型的那篇论文&#xff0c;被问到与SELF-RAG有何区别。所以&#xff0c;大概看了一下SELF-RAG这篇论文&#xff0c;确实很像&#xff0c;这些基于LLM针对下游任务的模型架构和方法&#xff0c;本来就很像。不过…

accelerate笔记:实验跟踪

Accelerate支持七种集成的跟踪器&#xff1a; TensorBoardWandBCometMLAimMLFlowClearMLDVCLive要使用这些跟踪器&#xff0c;可以通过在 Accelerator 类的 log_with 参数中传入所选类型来实现 from accelerate import Accelerator from accelerate.utils import LoggerTypeac…

Yolo-v5模型训练速度,与GeForce的AI算力描述

1.GeForce RTX3070 Ti官网参数&#xff1a; GeForce RTXTM 3070 Ti 和 RTX 3070 显卡采用第 2 代 NVIDIA RTX 架构 - NVIDIA Ampere 架构。该系列产品搭载专用的第 2 代 RT Core &#xff0c;第 3 代 Tensor Core、全新的 SM 多单元流处理器以及高速显存&#xff0c;助您在高性…

北斗RTK+UWB定位的优势

在当今科技飞速发展的时代&#xff0c;定位技术的应用已渗透到我们生活的方方面面。从导航、物流到无人驾驶、智能制造&#xff0c;精准定位技术无处不在。而北斗RTK&#xff08;Real-Time Kinematic&#xff0c;实时动态&#xff09;和UWB&#xff08;Ultra-Wideband&#xff…

闭眼推荐的,新手教师工具

亲爱的老师们&#xff0c;尤其是那些刚踏入教育界的新手教师们&#xff0c;还在为如何高效管理课堂、如何制作精美的教学材料而头疼吗&#xff1f;让我来分享几款教育界口碑爆棚的工具。 易查分小程序 易查分是一款超级方便的成绩查询工具&#xff0c;一分钟就能上传成绩并生成…

[经验] 腰果树的外观特征和特点是什么 #媒体#微信

腰果树的外观特征和特点是什么 腰果树是一种生长在热带和亚热带地区的落叶乔木&#xff0c;其叶子为互生&#xff0c;倒披针形或披针形&#xff0c;整个树枝条生长勃勃&#xff0c;长势喜人。 腰果树的树皮是灰色或深褐色的&#xff0c;有着纵向裂缝&#xff0c;树皮粗糙而有光…

【Mybatis】源码分析-高级应用

1、Mybatis配置文件深入理解 1.2、动态SQL语句 Mybatis 的映射⽂件中&#xff0c;前⾯我们的 SQL 都是⽐较简单的&#xff0c;有些时候业务逻辑复杂时&#xff0c;我们的 SQL是动态变化的&#xff0c;此时在前⾯的学习中我们的 SQL 就不能满⾜要求了。 1.2.1、条件判断 我们根…

OrangePi KunPengPro | linux系统下挂载U盘

OrangePi KunPengPro | linux系统下挂载U盘 时间&#xff1a;2024年6月6日21:32:53 文章目录 OrangePi KunPengPro | linux系统下挂载U盘1.参考2.操作fdisk -l 列出系统上所有磁盘的分区表信息将 /dev/sda1 分区挂载到 /mnt/udisk/ 目录显示文件系统的磁盘空间使用情况卸载文件…

【C++】问题及补充(2)

string s2“hello word”;是怎么进行隐式类型转换的 在这里&#xff0c;"hello world"是一个C字符串常量&#xff0c;而s2是一个std::string类型的变量。当你将C字符串常量赋值给一个std::string类型的变量时&#xff0c;会发生隐式类型转换。编译器会将C字符串常量转…

机器学习笔记 - 本地windows 11 + PyCharm运行stable diffusion流程简述

一、环境说明 硬件:本地电脑windows11、32.0 GB内存、2060的6G的卡。 软件:本地有一个python环境,主要是torch 2.2.2+cu118 二、准备工作 1、下载模型 https://huggingface.co/CompVishttps://huggingface.co/CompVis 进入上面的网址,我这里下载的是这个里面的 …

Go微服务: 分布式Cap定理和Base理论

分布式中的Cap定理 CAP理论 C: 一致性&#xff0c;是站在分布式的角度&#xff0c;要么读取到数据&#xff0c;要么读取失败&#xff0c;比如数据库主从&#xff0c;同步时的时候加锁&#xff0c;同步完成才能读到同步的数据&#xff0c;同步完成&#xff0c;才返回数据给程序&…