首页 文章 精选 留言 我的

精选列表

搜索[双足行走],共9147篇文章
优秀的个人博客,低调大师

黑白双鹰,白金降临:技嘉猎鹰 / 冰猎鹰白金电源 4 月 27 日开售

技嘉科技宣布,全新 EAGLE 猎鹰白金、冰猎鹰白金电源系列将于 4 月 27 日在京东平台正式发售。新品提供 750W、850W、1000W 三档功率,黑色与白色两款外观可选,专为电竞玩家、内容创作者及高端 DIY 用户打造,带来新一代高效稳定的供电方案。 该系列通过 80PLUS 白金认证,50% 负载下转换效率(115V超过 92%,230V超过94%)。内置氮化镓(GaN)芯片,有效降低待机损耗,运行更节能。产品全面支持 Intel ATX 3.1 与 PCIe Gen 5.1 标准,可承受 200%额定瞬时峰值功耗,原生 12V-2x6 供电线直连显卡,无需转接,安全可靠。 此外,新品配备两段式智能 OPP 保护及过载、过压、浪涌、欠压、空载、短路、过温等全方位防护。内部采用半数位 LLC 架构、日系电容、真 FDB 静音风扇,并搭配双层 PCB、三防漆工艺与纯铜蟒纹线材,兼顾稳定性、耐用性与装机美观度。产品已通过CE及3C 认证,支持 5000 米高海拔稳定运行,适应各类复杂环境。 技嘉将持续深耕 DIY 硬件研发,为用户带来更高品质、高性能的 PC 产品,助力玩家与创作者释放硬件潜能。产品将于 4 月 27 日在技嘉京东官方旗舰店率先上架,敬请关注。 技嘉京东官方旗舰店链接: GP-EG1000PM PG5 https://item.jd.com/100348134054.html GP-EG1000PM PG5 ICE https://item.jd.com/100348102914.html GP-EG850PM PG5 https://item.jd.com/100348143054.html GP-EG850PM PG5 ICE https://item.jd.com/100348124558.html GP-EG750PM PG5 https://item.jd.com/100260903593.html GP-EG750PM PG5 ICE https://item.jd.com/100348131812.html

优秀的个人博客,低调大师

OpenAI 奥尔特曼炮轰 Anthropic:超级碗广告“撒谎”、长期使用双标话术

OpenAI 首席执行官萨姆·奥尔特曼在 X 平台公开发文,严厉指责竞争对手 Anthropic 在超级碗期间投放的广告存在“明显的不实信息”,并揭露其长期以来惯用“含糊其辞的双面话术”。 这场口水战的导火索是 Anthropic 发布的最新宣传片。虽然广告中并未直接点名 OpenAI 或 ChatGPT,但其宣称“Claude 回复不受广告商影响、无第三方植入”的说法,被外界普遍解读为是对 OpenAI 近期测试广告模式的冷嘲热讽。 对此,奥尔特曼强硬回应称,OpenAI 绝对不会以对方描述的那种“愚蠢方式”投放广告,并强调广告完全独立于回答内容,绝不影响 AI 的客观性。 除了反击广告内容,奥尔特曼还从市场体量和商业模式上对 Anthropic 进行了全方位“降维打击”。他透露,仅得克萨斯州免费使用 ChatGPT 的用户数就已超过全美 Claude 的总用户数,暗示双方根本不在一个量级。他抨击 Anthropic 定价昂贵且奉行“威权主义”,妄图管控用户并插手他人的商业模式,而 OpenAI 则致力于让数十亿普通民众都能免费获取 AI 技术。

优秀的个人博客,低调大师

阿里云Milvus 2.5:支持全文检索,1次查询实现文本+向量双精度匹配

随着大模型时代带来的各种新型应用探索,结合传统基于文本匹配的精确检索与语义检索所带来的增益日益显著,尤其在一些深度依赖关键字词匹配的场景中,这种需求变得尤为关键。目前,阿里云向量检索服务 Milvus 版(简称阿里云 Milvus)集成开源 Milvus2.5版本内核,在支持向量检索的基础上,新增支持原生全文检索、基于特定词汇的精准文本匹配等功能,在 RAG、多模态搜索等场景下搜索精度明显提升,使用体验大幅优化。 阿里云 Milvus 是一款全托管向量检索引擎,100%兼容开源 Milvus,提供大规模AI向量数据的相似性检索服务。凭借其开箱即用的特性、灵活的扩展能力和全链路监控告警,成为多样化 AI 应用场景的理想选择。本次2.5版本的上线,使得阿里云 Milvus 能够实现从文本输入到向量检索的端到端流程,在电商、法律、新闻等多行业搜索场景中发挥多模态融合和场景化增强的价值。 全文检索(Full Text Search) 全文检索能力基于内置的 Sparse-BM25 算法,首次实现原生全文检索功能,与现有的语义搜索能力形成完美互补。 核心能力: 内置分词器,无需额外预处理:通过内置分词器(Analyzer)与稀疏向量提取能力, 可直接接受文本输入,自动完成分词、停用词过滤与稀疏向量提取,无需依赖外部模型(如BGE-M3等)。 实时 BM25 统计:数据插入时动态更新词频(TF)与逆文档频率(IDF),确保搜索结果的实时性与准确性。 混合搜索性能增强:基于近似最近邻(ANN)算法的稀疏向量检索,性能远超传统关键词系统,支持亿级数据毫秒级响应,同时兼容与稠密向量的混合查询。 典型应用场景: 法律文档库中的快速定位特定条款中的专业术语等罕见词。 电商平台结合商品描述的关键词与语义特征,提升搜索相关性,兼顾召回率与精确性。 全文检索 实现全文检索功能主要步骤: 创建 Collections:设置带有必要字段的 Collections,并定义一个将原始文本转换为稀疏向量的函数 插入数据:将原始文本文档插入 Collections 执行搜索:使用查询文本搜索你的 Collections 并检索相关结果 代码示例如下: from pymilvus import MilvusClient, DataType, Function, FunctionType client = MilvusClient(uri="http://localhost:19530") # 定义 Collection# id:作为主键,由auto_id=True 自动生成# text:存储原始文本数据,用于全文搜索操作。数据类型必须是VARCHAR ,因为VARCHAR 是 Milvus 用于文本存储的字符串数据类型。设置enable_analyzer=True 以允许 Milvus 对文本进行标记化# sparse:矢量字段:预留矢量字段,用于存储内部生成的稀疏嵌入,以进行全文搜索操作。数据类型必须是SPARSE_FLOAT_VECTORschema = client.create_schema()schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True)schema.add_field(field_name="sparse", datatype=DataType.SPARSE_FLOAT_VECTOR) # 定义一个将文本转换为稀疏向量表示的函数bm25_function = Function( name="text_bm25_emb", # Function name input_field_names=["text"], # Name of the VARCHAR field containing raw text data output_field_names=["sparse"], # Name of the SPARSE_FLOAT_VECTOR field reserved to store generated embeddings function_type=FunctionType.BM25,)schema.add_function(bm25_function) # 向量配置索引index_params = client.prepare_index_params()index_params.add_index( field_name="sparse", index_type="AUTOINDEX", metric_type="BM25") # 创建 Collectionsclient.create_collection( collection_name='demo', schema=schema, index_params=index_params) # 插入文本数据client.insert('demo', [ {'text': 'information retrieval is a field of study.'}, {'text': 'information retrieval focuses on finding relevant information in large datasets.'}, {'text': 'data mining and information retrieval overlap in research.'},]) # 执行全文搜索search_params = { 'params': {'drop_ratio_search': 0.2},} client.search( collection_name='demo', data=['whats the focus of information retrieval?'], anns_field='sparse', limit=3, search_params=search_params) 文本匹配(Text Match) 支持基于特定词汇的精准文本匹配搜索,可结合标量过滤进一步细化查询结果,满足精确检索的需求。 核心能力: 词项预处理:利用分词器与索引技术,对文本进行标准化处理(如大小写转换、词干提取)。 混合查询模式:在向量相似性搜索的基础上,叠加标量条件过滤(如“日期 > 2023”),实现多维度精准检索。 性能优化:索引构建与查询执行效率提升,满足高并发场景下的低延迟需求。 典型应用场景: 新闻平台中按标题关键词+时间范围过滤,快速定位相关报道。 企业知识库中结合员工ID与文档关键词,实现权限内的精确检索。 实现本文匹配的代码示例如下,如若配置文本分析器后续便可结合标量过滤功能做文本匹配过滤以细化查询结果: 启用文本匹配 from pymilvus import MilvusClient, DataType schema = MilvusClient.create_schema(auto_id=True, enable_dynamic_field=False) schema.add_field( field_name='text', datatype=DataType.VARCHAR, max_length=1000, enable_analyzer=True, # 是否启用该字段的文本分析 enable_match=True # 是否启用文本匹配) 可选:配置分析器 analyzer_params={ "type": "english"} schema.add_field( field_name='text', datatype=DataType.VARCHAR, max_length=200, enable_analyzer=True, analyzer_params=analyzer_params, enable_match=True, ) 使用文本匹配搜索 # Match entities with `keyword1` or `keyword2`filter = "TEXT_MATCH(text, 'keyword1 keyword2')" result = MilvusClient.search( collection_name="YOUR_COLLECTION_NAME", anns_field="embeddings", data=[query_vector], filter=filter, search_params={"params": {"nprobe": 10}}, limit=10, output_fields=["id", "text"]) 使用文本匹配查询 filter = "TEXT_MATCH(text, 'keyword1') and TEXT_MATCH(text, 'keyword2')" result = MilvusClient.query( collection_name="YOUR_COLLECTION_NAME", filter=filter, output_fields=["id", "text"]) 此外,阿里云 Milvus 2.5新增支持分页查询和标量过滤模板等功能,进一步提升了产品的易用性和性能。 立即体验 我们诚邀您立即体验阿里云向量检索服务Milvus 2.5版本的强大功能! 产品新用户可免费试用入门版8 vCPU 32 GiB1个月,领取地址(https://x.sm.cn/4AqoOSM) 此外,阿里云为了回馈新老用户,推出了重大优惠: 向量检索服务Milvus版 限时年付5折! 阿里云向量检索服务 Milvus 版,将持续打磨产品,不断优化产品的功能、性能和使用体验,为用户提供更加专业、灵活、高效的向量搜索引擎服务,助力企业轻松应对海量非结构化数据管理挑战,实现业务价值最大化,欢迎大家前往产品控制台购买体验!

优秀的个人博客,低调大师

【敢于非凡】Solon v2.9.4,v3.0.0-RC 双版发布(支持 Java 23)

本来没有,难得弱小生来。借华为的话,“我们敢于非凡”。七年时间,我们不断变强!越来越强!还会更强! Solon 框架! Java “新式”应用开发框架。开放原子开源基金会,孵化项目。从零开始构建(非 java-ee 架构),有灵活的接口规范与开放生态。 追求: 更快、更小、更简单 提倡: 克制、简洁、高效、开放、生态 有什么特点? 特点 描述 更高的计算性价比 并发高 300%;内存省 50% 更快的开发效率 代码少;入门快;调试重启快 10 倍 更好的生产与部署体验 打包小 90% 更大的兼容范围 非 java-ee 架构;同时支持 java8 ~ java22,graalvm native image 入门探索视频(用户录制): v2.9.4 更新了什么? 新增 solon-web-vertx 插件 新增 solon 分类注入支持体系 新增 solon 分类构建支持体系 添加 solon Duration 类型配置注入 添加 solon AppContext::beanExclude 方法 添加 solon AppContext::beanDeliver 方法 添加 solon Bean:delivered 替代 registered 添加 solon Component:delivered 替代 registered 添加 solon-boot-vertx websocket 支持 添加 solon-web-cross CrossInterceptor::pathPatterns() 方法 添加 solon Router:getAll(), getBy(path) 方法 添加 solon Action 过滤器体系(替代 Before,After 体系) 添加 Context::sessionReset 方法 添加 solon Props:toBean 方法(替代 Props:getBean) 添加 solon-scheduling CommandExecutorProxy 原型代理支持 添加 solon-data DsUtils.observeDs 方法 添加 solon-cloud CloudEventHandlerPlus 原型代理支持 添加 solon-cloud CloudConfigHandler 原型代理支持 添加 solon-cloud CloudEventHandler 原型代理支持 添加 solon-cloud-gateway X_Forwarded_Host 和 https 转发支持 添加 solon-cloud-gateway RewritePathFilterFactory 添加 solon-cloud-gateway QueryPredicateFactory 优化 kafka-solon-cloud-plugin 添加自动延时重试模拟实现 优化 grpc-solon-cloud-plugin GrpcClient 注解处理添加必须 优化 thrift-solon-cloud-plugin ThriftClient 注解处理添加必须 调整 solon Before,After Handler 体系标为弃用 调整 solon Props:getBean 标为弃用 调整 solon NvMap:getBean 标为弃用 调整 solon Gateway:find 改为 public 调整 solon-logging OutputStreamAppender 彩色打印 调整 solon Constants 内部类改为接口类型 凋整 solon-cloud-gateway 路由处理体系,支持路由多协议头扩展 调整 solon-scheduling scheduled 内部实现类(强调原型代理概念 调整 solon ContextPathFilter index 改为 -990 调整 solon-i18n I18nFilter index 改为 -980 提醒 solon AppContext::beanAroundAdd 添加弃用打印日志 提醒 solon 添加不支持单例的打印日志 修复 solon BeanWrap::rawClz 处理 anonymousClass 失误的问题 修复 jdk21 + win10 + solon-logging-simple 打包后无法输出日志的问题 取消 Ds 注解(未启用) 取消 HandlerProxy ,不太合理(尤其是对本地网关) 取消 Solon:versionCode snack3 升为 3.2.111 wood 升为 1.3.6 redisson 升为 3.35.0 bean-searcher 升为 4.3.2 beetlsql 升为 3.30.13-RELEASE asm 升为 9.7 v3.0.0-RC 更新了什么? 详见:《Solon v3.x 更新与兼容说明》- 清单太长了! 项目仓库地址? gitee:https://gitee.com/opensolon/solon github:https://github.com/opensolon/solon 官网? https://solon.noear.org

优秀的个人博客,低调大师

PrettyZoo V1.5.0,颜值与功能双在线的 Zookeeper 可视化工具

PrettyZoo 简介 PrettyZoo 是一款基于 JavaFX 和 Curator 实现的高颜值开源 Zookeeper 可视化工具 V1.5.0 新特性 支持为 zookeeper 连接设置别名 强制默认数据编码为 UTF-8 4-Letter-command 增加校验 下载地址:https://github.com/vran-dev/PrettyZoo/releases 项目主页:https://github.com/vran-dev/PrettyZoo 更多特性 支持 SSH-Tunnel 连接 节点 CRUD (增删改查) 节点数据 pretty format,目前支持 JSON、XML 支持命令行操作 支持 4-letter command 支持配置导入 、导出 更多详细内容请查看项目主页

优秀的个人博客,低调大师

每日一博 | 记一次 MySQL 主从双写导致的数据丢失问题

作者:戴骏贤 网易游戏 技术部资深数据库系统工程师。 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。 一、问题起源 不久前用户反馈部门的 MySQL 数据库发生了数据更新丢失。为了解决这个问题,当时对用户使用的场景进行了分析。发现可能是因为用户在两台互为主从的机器上都进行了写入导致的数据丢失。 如图所示,是正常和异常情况下应用写入数据库的示例。随后在更加深入调查问题的过程中,DBA 发现了故障引起数据丢失的原因: 如图 1-2 所示为故障具体过程的还原。从图中可以看出在第 3 步 DP 上的写入操作,在恢复 DA 到 DP 的同步之后,覆盖了第 4 步 DA 上的写入。因此导致了最终两台机器数据不一致,并且有一部分数据更新丢失。 在这里相信读者都会有一个疑问, 在第 4 步之后数据变成了(id : 1 ,name : name4),那么第 3 步操作的时候写入的语句是update t20200709 set name = 'name3' where id =1 and name='name2',在第 5 步恢复同步的时候这条语句在 DA 上重放应该不会被成功执行,毕竟 Where 条件都不匹配了。而且在 DP 产生的 Binlog 中,确实也记录了 SQL 语句的 Where 条件,无论从哪个角度上来看第 3 步的 SQL 语句都不应该被重放成功。 ### UPDATE `test`.`t20200709`### WHERE### @1=1 /* INT meta=0 nullable=0 is_null=0 */### @2='name2' /* VARSTRING(255) meta=255 nullable=1 is_null=0 */### SET### @1=1 /* INT meta=0 nullable=0 is_null=0 */### @2='name3' /* VARSTRING(255) meta=255 nullable=1 is_null=0 */# at 684315240 那么这个问题难道是 MySQL 自身的 Bug,抑或是 MySQL 在某些特殊参数或者条件下的正常表现?对于这个问题,本文将可能的给出这个问题的详细解释和分析。 二、Row 格式下 RelayLog 的重放 2.1 BEFOR IMAGE && AFTER IMAGE && binlog_row_image 参数 在最后解释本文最初提出的问题前,需要先来看下 RelayLog 是怎么被重放的。一般情况下,当有 DML 语句变更数据库中的数据的时候,Binlog 会记录下事件描述信息、BEFORE IMAGE 和 AFTER IMAGE 等信息。在这里有一个概念 BEFORE IMAGE 和 AFTER IMAGE 需要先介绍下: 1. BEFORE IMAGE : 前镜像,既数据修改前的样子。 2. AFTER IMAGE : 后镜像,既数据修改后的样子。 为了方便理解,这里贴一个 Binlog 的例子。假设当前有表 t20200709,然后表中数据如下: mysql> select * from t20200709 ;+----+-------+| id | name |+----+-------+| 1 | name4 |+----+-------+1 rows in set (0.00 sec) 之后执行 SQL 语句update t20200709 set name =1 where id = 1; mysql> update t20200709 set name =1 where id = 1;Query OK, 1 row affected (0.00 sec)Rows matched: 1 Changed: 1 Warnings: 0 然后来看下 Binlog 中的记录: #200715 17:28:28 server id 15218 end_log_pos 400 CRC32 0xe4dedec0 Update_rows: table id 4034114356 flags: STMT_END_F### UPDATE `test`.`t20200709`### WHERE### @1=1 /* INT meta=0 nullable=0 is_null=0 */### @2='name4' /* VARSTRING(255) meta=255 nullable=1 is_null=0 */### SET### @1=1 /* INT meta=0 nullable=0 is_null=0 */### @2='1' /* VARSTRING(255) meta=255 nullable=1 is_null=0 */# at 400 可以见得,在修改之前 name 字段的值是 name4,在 Binlog 中用 Where 条件@2='name4'来指明,而修改后的 name 的值是 '1',在 Binlog 中就是@2='1'来指明。因此 BEFORE IMAGE 就是 Binlog 中 WHERE 到 SET 的部分。而 AFTER IMAGE 就是 SET 之后的部分。 那么 DELETE,UPDATE 和 INSERT 语句被记录在 Binlog 中的时候,是否都有 BEFORE IMAGE 和 AFTER IMAGE?其实不是所有的 DML 事件类型都拥有两个 IMAGE 的,参见图 2-2 可知只有 UPDATE 语句,会同时拥有 BEFORE IMAGE 和 AFTER IMAGE。 BEFOR IMAGE 和 AFTER IMAGE 默认会记录所有的列的变更,因此会导致 Binlog 的内容变得很大。那么有没有参数可以控制 IMAGE(对于 BEFOR IMAGE 和 AFTER IMAGE 以下合并简称为 IMAGE)的行为?MySQL 5.7 之后引入了一个新的参数binlog_row_image 。 参数说明: binlog_row_image:https://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html#sysvar_binlog_row_image 用于控制 IMAGE 的行为。 binlog_row_image 参数的值有三个: 1. full:Log all columns in both the before image and the after image. 既所有的列的值的变更,都会在 IMAGE 中记录。系统默认是 full。 2. minimal:Log only those columns in the before image that are required to identify the row to be changed; log only those columns in the after image where a value was specified by the SQL statement, or generated by auto-increment. BEFOR IMAGE 只记录哪些能够唯一标识数据的列,比如主键,唯一键等。AFTER IMAGE 只记录了变更的列。可以看出,minimal 会有效的减少 Binlog 的大小。 3. noblob:Log all columns (same as full), except for BLOBand TEXTcolumns that are not required to identify rows, or that have not changed. 对于其他列的行为都和 full 参数一样。但是对于 BLOB 和 TEXT,在不是可以标识数据行或者有变更的情况下不做记录。 参数说明: BLOB:https://dev.mysql.com/doc/refman/5.7/en/blob.htmlTEXT:https://dev.mysql.com/doc/refman/5.7/en/blob.html 可以看出 binlog_row_image 可以有效控制Binlog的大小,但是如果要保证数据的一致性,最好的值就是设置为 full。 2.2slave_rows_search_algorithms 参数 前文提到了 IMAGE 与 binlog_row_image 相关的内容。本节开始将主要介绍 Relay Log 的重放的时候,对于被重放的记录的查找逻辑。对于 DELETE 和 UPDATE 操作,需要先对数据库中的记录进行检索以确定需要执行 Binlog 重放的数据。如果从库的表上没有主键或唯一键时,则需要根据每一个行记录 BEFOR IMAGE 在所有数据中进行一次全表扫描。在大多数情况下这种开销非常巨大,会导致从库和主库的巨大延迟。从 MySQL 5.6 开始提供了参数slave_rows_search_algorithms 参数说明:slave_rows_search_algorithms:https://dev.mysql.com/doc/refman/5.7/en/replication-options-replica.html#sysvar_slave_rows_search_algorithms 用于控制在 Relay Log 执行重放的时候对于记录的检索行为。其基本的思路是收集每条记录的 BEFOR IMAGE 信息,然后根据 BEFOR IMAGE 的信息在被重放的表中检索对应的记录。根据 MySQL 的文档,检索数据的方式有如下的几种: 1.INDEX_SCAN 2.TABLE_SCAN 3.HASH_SCAN 如上三个方式可以两两组合并赋值给slave_rows_search_algorithms参数。MySQL 文档也给出了如下的说明: The default value isINDEX_SCAN,TABLE_SCAN, which means that all searches that can use indexes do use them, and searches without any indexes use table scans. To use hashing for any searches that do not use a primary or unique key, setINDEX_SCAN,HASH_SCAN. SpecifyingINDEX_SCAN,HASH_SCANhas the same effect as specifyingINDEX_SCAN,TABLE_SCAN,HASH_SCAN, which is allowed. Do not use the combinationTABLE_SCAN,HASH_SCAN. This setting forces hashing for all searches. It has no advantage overINDEX_SCAN,HASH_SCAN, and it can lead to “record not found” errors or duplicate key errors in the case of a single event containing multiple updates to the same row, or updates that are order-dependent. 1. INDEX_SCAN,TABLE_SCAN: 可以看出在默认的情况下,既INDEX_SCAN,TABLE_SCAN如果有主键或者唯一键,则通过主键或者唯一键来查询数据并重放 AFTER IMAGE。如果没有主键或者唯一键,则通过二级索引完成这个工作。如果什么都没有,则使用全表扫描的方式。 2. INDEX_SCAN,HASH_SCAN : 在表有主键或者唯一键的情况下, INDEX_SCAN,HASH_SCAN 配置也是使用的主键或者唯一键去定位数据。在表有二级索引或者完全没有索引的情况下会使用 HASH_SCAN 的方法。 可以见得 Slave 检索需要重放的数据的时候,三个检索方式的优先级是 Index Scan > Hash Scan > Table Scan 相信读者在这里会有 2 个疑问: 1. Hash Scan 的原理是什么?它和 Table Scan 以及 Index Scan 有什么区别?文档中还提到了 Hash scan over index 这个和 Index 有什么关系? 2. 前文提到在表没有主键或者唯一键的时候,会通过二级索引来定位数据。假设表中有 N 个二级索引(包括单列索引和联合索引),哪个二级索引会被选中? 2.3 Hash Scan && Table Scan && Index Scan 实现 分析 MySQL 源码可知最后决定使用哪个检索方式是在函数 Rows_log_event::decide_row_lookup_algorithm_and_key 里面实现的。 9745 void9746 Rows_log_event::decide_row_lookup_algorithm_and_key()9747 {9748... ...9781 /* PK or UK => use LOOKUP_INDEX_SCAN */9782 this->m_key_index= search_key_in_table(table, cols, (PRI_KEY_FLAG | UNIQUE_KEY_FLAG));9783 if (this->m_key_index != MAX_KEY)9784 {9785 DBUG_PRINT("info", ("decide_row_lookup_algorithm_and_key: decided - INDEX_SCAN"));9786 this->m_rows_lookup_algorithm= ROW_LOOKUP_INDEX_SCAN;9787 goto end;9788 }... ...9790 TABLE_OR_INDEX_HASH_SCAN:... ...9808 TABLE_OR_INDEX_FULL_SCAN:... ...9827 end:... ... 在 9782 行会先检索表中是否有主键和唯一键。之后在 TABLE_OR_INDEX_HASH_SCAN 和 TABLE_OR_INDEX_FULL_SCAN 决定最后使用哪种检索方式。在 do_apply_event 函数中,会根据 decide_row_lookup_algorithm_and_key 的结果去调用函数: 11286 switch (m_rows_lookup_algorithm)11287 {11288 case ROW_LOOKUP_HASH_SCAN:11289 do_apply_row_ptr= &Rows_log_event::do_hash_scan_and_update;11290 break;1129111292 case ROW_LOOKUP_INDEX_SCAN:11293 do_apply_row_ptr= &Rows_log_event::do_index_scan_and_update;11294 break;1129511296 case ROW_LOOKUP_TABLE_SCAN:11297 do_apply_row_ptr= &Rows_log_event::do_table_scan_and_update;11298 break;1129911300 case ROW_LOOKUP_NOT_NEEDED:11301 DBUG_ASSERT(get_general_type_code() == binary_log::WRITE_ROWS_EVENT);1130211303 /* No need to scan for rows, just apply it */11304 do_apply_row_ptr= &Rows_log_event::do_apply_row;11305 break;1130611307 default:11308 DBUG_ASSERT(0);11309 error= 1;11310 goto AFTER_MAIN_EXEC_ROW_LOOP;11311 break;11312 } 可以见得: 1. do_hash_scan_and_update: 对应 hash_scan 方式。 2. do_index_scan_and_update: 对应 index_scan 方式。 3. do_table_scan_and_update:对应 table_scan 方式。 接下来分别介绍下这三个函数所完成的内容。 2.3.1 do_hash_scan_and_update do_hash_scan_and_update 函数主要实现了 Hash Scan 检索数据的功能。在实现方式上又可以分为 H --> Hash Scan 和 Hi --> Hash over Index 两种方式。首先来看下 Hash Scan 的实现方法,图 2-5 给出 Hash Scan 的实现逻辑。 可以见得 Binlog 中的 BI 在 Slave 上会被处理到一个 Hash 表中。因为没有合适的索引可以使用,所以使用全表扫描的方式每获取一条记录就根据记录的值计算一个 hash 值,然后在 BI 的 Hash 表中匹配。如果匹配到了 BI,则重放并删除 Hash 表中的记录。 如果 test06 表中 id 列上有索引,那么在 Slave 重放的使用会使用 Hi --> Hash over index 的方式。如图 2-6 所示给出了 Hash over Index 方式(以下均简称 Hi)的实现逻辑。 可以见得如果通过 Hi 方式进行重放,则会对使用的二级索引生成一个 m_distinct_keys 结构,这个结构存放着这个 BI 中这个索引所有的去重值。然后对于 Slave 上的 test06 表通过 m_distinct_keys 中的每一个值在二级索引上进行遍历,遍历获取的记录与 m_hash 中的结果对比并执行重放逻辑。 ps : 对于 Hash Scan 方式还要一个比较迷惑的特性,读者可以参考下这篇文章[技术分享 | HASH_SCAN BUG 之迷惑行为大赏] 2.3.2 do_index_scan_and_update Index Scan 方式会通过索引检索 Slave 上需要重放的数据。通过索引检索数据的方式又可以分为: 1. 通过主键/唯一键索引检索数据。 2. 通过二级索引检索数据。 在通过主键或者唯一键索引检索数据的时候会调用 do_index_scan_and_update 函数,在函数逻辑中直接通过主键/唯一键索引返回了记录然后重放 Binlog。 而在通过二级索引检索数据的时候,会对二级索引返回的数据与 BI 中每一条记录做比较,如果一致就会重放 Binlog。 至此可以发现 Index Scan 下对于主键/唯一键和二级索引的实现逻辑有一些不同。对于主键/唯一键,对于索引到的记录并不会和 BI 中的每一个列做比较,而二级索引获取到的数据会与 BI 中每一个列做比较,如果不一致而不会重放并报错。 2.3.3 do_table_scan_and_update Table Scan 的实现相对简单,如果没有任何的索引可以使用,只能通过全表扫描的方式获取每一行数据并和BI中的每一行做比较。因此如果 Slave 上的数据和 Master 上的数据不一致,也会如图 2-9 中所示一样报错。关于 Table Scan 更加具体的实现方式,读者可以参考 MySQL 源码 sql/log_event.cc 文件中的 do_table_scan_and_update 函数,在这里就不过多的展开。 2.3.4 小结 至此可以回答本文之前提出的这个问题了: Hash scan 方法的原理是什么?它和 Table scan 以及 Index scan 有什么区别?文档中还提到了 Hash scan over index 这个和 Index 又有什么关系? 可以见得,Hash Scan 的原理是将 BI 每一行的内容都放入一个 Hash 表中。如果可以使用二级索引(既 Hash scan over index 这个方式),则额外的对 BI 中二级索引的值生成一个 Hash 结构,并且将 BI 中二级索引列的去重值放入这个 Hash 结构中。之后不管是通过全表扫描还是索引的方式获取数据,都会通过 Hash 结构去定位 BI 中的数据。对于 Table Scan 和 Index Scan 在获取表中的每一行之后,都需要去和 BI 中的记录做一次查找和比较(有主键或者唯一键的时候不做比较),而 BI 的每一行并没有生成类似于 Hash 的结构,因此从算法的时间复杂度效率上来说是属于 O(n^2) 的。而 Hash Scan 在获取一条记录之后也需要根据 BI 生成的 Hash 结构中查找记录,但是对于 Hash 结构的查找来说效率是 O(1),因此可以忽略不计。由此可以看出,在没有主键的情况下 Hi 和 Ht 方式的效率是会比 Table Scan 和 Index Scan 来的高一些。 同时到这里,也可以回答本文开头的问题,为什么当前表中的记录有一列值已经和 BI 中的记录不一致了,Binlog 中的操作还会重放。原因就是因为在默认的 INDEX_SCAN,TABLE_SCAN 方式下,对于有主键/唯一键的表不会去比较 BI 中的记录是否和检索到的数据一致。 2.4 Hash Scan Over Index && Index Scan 中二级索引的选择 前文提到了在有二级索引的情况下,Hash Scan 和 Index Scan 都会选择二级索引进行扫描。如果表中存在多个二级索引,MySQL 会选择哪个?通过源码分析,最后惊讶的发现,在 binlog_row_image 参数是 Full 的情况下,如果表中存在多个二级索引,MySQL 会默认选择使用第一个索引进行重放。在 decide_row_lookup_algorithm_and_key 函数中,除了决定了使用哪种方式检索数据以外(例如使用 Hash Scan 还是 Table Scan),也决定了后续使用哪个索引。 如图 2-10 给出了选择二级索引的时候的逻辑。可以发现如果在遍历的过程中,找到了第一个所有的列都在 BI 中 key,则会使用这个 key。给出一个例子,test06 的表结构和表中数据如下: *************************** 1. row *************************** Table: test06Create Table: CREATE TABLE `test06` ( `id` int(11) NOT NULL, `name` varchar(255) DEFAULT NULL, `c1` int(11) DEFAULT NULL, KEY `k1` (`id`), KEY `k2` (`id`,`name`), KEY `k3` (`c1`,`name`)) ENGINE=InnoDB DEFAULT CHARSET=utf81 row in set (0.13 sec)mysql> select * from test06 ;+------+-------+------+| id | name | c1 |+------+-------+------+| 2582 | name3 | 1 || 2582 | name4 | 1 || 1 | name1 | 0 || 1 | name2 | 0 || 1 | name3 | 0 |+------+-------+------+5 rows in set (0.00 sec) 在 Master 上执行 SQL,同时 Master 上的执行计划如下: delete from test06 where id = 1 and name ='name3' and c1=0;mysql> explain delete from test06 where id = 1 and name ='name3' and c1=0;+----+-------------+--------+------------+-------+---------------+------+---------+-------------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+--------+------------+-------+---------------+------+---------+-------------+------+----------+-------------+| 1 | DELETE | test06 | NULL | range | k1,k2,k3 | k2 | 772 | const,const | 1 | 100.00 | Using where |+----+-------------+--------+------------+-------+---------------+------+---------+-------------+------+----------+-------------+1 row in set (0.00 sec) 可以见得,在 Master 上优化器选择了 k2 这个联合索引。通过 GDB 跟踪 Slave 的进程,在 log_event.cc 第 9733 行打断点: 9714 if (key_type & MULTIPLE_KEY_FLAG && table->s->keys) 9715 { 9716 DBUG_PRINT("debug", ("Searching for K.")); 9717 for (key=0,keyinfo= table->key_info ; 9718 (key < table->s->keys) && (res == MAX_KEY); 9719 key++,keyinfo++) 9720 { 9721 /* 9722 - Skip innactive keys 9723 - Skip unique keys without nullable parts 9724 - Skip indices that do not support ha_index_next() e.g. full-text 9725 - Skip primary keys 9726 */ 9727 if (!(table->s->keys_in_use.is_set(key)) || 9728 ((keyinfo->flags & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME) || 9729 !(table->file->index_flags(key, 0, true) & HA_READ_NEXT) || 9730 (key == table->s->primary_key)) 9731 continue; 9732 9733 res= are_all_columns_signaled_for_key(keyinfo, bi_cols) ? 9734 key : MAX_KEY; 9735 9736 if (res < MAX_KEY) 9737 DBUG_RETURN(res); 9738 } 9739 DBUG_PRINT("debug", ("Not all columns signaled for K.")); 9740 } 可以观察到这时候 m_key_index 的值是 0,并且观察 keyinfo 变量的值为: (gdb) print *keyinfo$4 = {key_length = 4, flags = 0, actual_flags = 0, user_defined_key_parts = 1, actual_key_parts = 1, unused_key_parts = 0, usable_key_parts = 1, block_size = 0, algorithm = HA_KEY_ALG_UNDEF, { parser = 0x0, parser_name = 0x0}, key_part = 0x7f2f4c015a00, name = 0x7f2f4c012bb1 "k1", rec_per_key = 0x7f2f4c012bc0, m_in_memory_estimate = -1, rec_per_key_float = 0x7f2f4c012bf8, handler = { bdb_return_if_eq = 0}, table = 0x7f2f4c92d1a0, comment = {str = 0x0, length = 0}} 接下来,删除 k1 这个索引,再来观察下 m_key_index 和 keyinfo 的值。 (gdb) print *keyinfo$7 = {key_length = 772, flags = 64, actual_flags = 64, user_defined_key_parts = 2, actual_key_parts = 2, unused_key_parts = 0, usable_key_parts = 2, block_size = 0, algorithm = HA_KEY_ALG_UNDEF, { parser = 0x0, parser_name = 0x0}, key_part = 0x7f2f4c92b680, name = 0x7f2f4c92e7d1 "k2", rec_per_key = 0x7f2f4c92e7d8, m_in_memory_estimate = -1, rec_per_key_float = 0x7f2f4c92e808, handler = { bdb_return_if_eq = 0}, table = 0x7f2f4ca9fd90, comment = {str = 0x0, length = 0}} 可以发现删除了 k1 之后,Slave 上就选择 k2 这个索引,和 Master上的执行计划选择的索引一致了。通过前面的源码分析和调试跟踪可以发现,MySQL 在 Slave 重放数据的时候(没有主键和唯一键的情况),选择的索引是第一个所有的列都在 BI 中存在的索引。因此可能存在 Slave 上选择的索引不是最优的导致 Slave 和 Master 有巨大延迟。 三、总结 至此前文提出的几个问题都基本清楚了,可以总结出如下的几点内容: 1. 在有主键或者唯一键的情况下,Slave 重放 Binlog 并不会去比较检索到的记录的每一列是否和BI相同,因此如果 Slave 和 Master 存在数据不一致,会直接覆盖 Slave 的数据而不会报错。 2. 在没有主键或者唯一键的情况下,Hash Scan / Hash Scan Over Index 的执行效率 在理论上分析高于 Table Scan 和Index Scan 。 3. 在没有主键或者唯一键的情况下,Slave 选择的二级索引是第一个所有的列都在 BI 中存在的索引,不一定是 Master 执行计划所选择的索引。 最后本文所有分析的源码都是基于 mysql-5.7.28 版本。限于作者的水平有限,如果文章中有错误之处,望大家不吝指正。 四、参考文献 [1]. MySQL 无主键延迟优化(slave_rows_search_algorithms). https://www.centos.bz/2018/01/mysql无主键延迟优化(slave_rows_search_algorithms) [2]. MySQL 5.7 贴心参数之 binlog_row_image. https://www.cnblogs.com/gomysql/p/6155160.html [3]. 技术分享 | delete大表slave回放巨慢的问题分析. https://mp.weixin.qq.com/s/aeZvPBhhbea058Kz1Pplpw [4]. Causes and Workarounds for Slave Performance Too Slow with Row-Based Events. https://www.percona.com/blog/2018/05/03/slave-performance-too-slow-with-row-based-events-causes-and-workarounds/ [5]. 技术分享 | 从库数据的查找和参数 slave_rows_search_algorithms. https://mp.weixin.qq.com/s/Jh1z6ir1YfI5BvmdBS1n8g [6]. 技术分享 | HASH_SCAN BUG 之迷惑行为大赏. https://mp.weixin.qq.com/s/7zOekpbHG4g5SQ-FyjKk0A 社区近期动态 点一下“阅读原文”了解更多资讯 本文分享自微信公众号 - 爱可生开源社区(ActiontechOSS)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册