使用KQL审计Azure Synapse Analytics数据库账号操作全流程
1. 从一次紧急排查说起为什么我们需要审计数据库操作上个月我们团队负责的一个核心数据仓库突然出现了一个数据异常。一个关键业务报表的汇总数字在凌晨时段发生了不预期的跳变直接影响了当天晨会的决策。业务方第一时间找到我们问题很明确数据在某个时间点被修改了但没人承认执行过相关操作。我们手头有Azure Synapse Analytics当时还叫Azure SQL DW的监控告警能知道有大量写入但具体是谁、通过什么账号、执行了哪条SQL语句却无从查起。那一刻我们深刻体会到在云原生数据平台中仅有资源层面的监控是远远不够的操作层面的审计Auditing才是厘清责任、追溯根因的生命线。传统的自建数据库我们可能会去翻数据库日志文件或者依赖第三方审计工具。但在Azure Synapse Analytics这样的PaaS服务里日志的存储、格式和查询方式都发生了变化。幸运的是Azure提供了一套强大且原生的日志与分析方案将诊断日志发送到Log Analytics工作区并使用Kusto查询语言Kusto Query Language, KQL进行查询分析。KQL正是为这类大规模日志数据实时分析而生的语言其表达能力和性能在面对海量审计日志时优势尽显。本文就将围绕这个真实场景手把手带你走通整个审计链路。我们将聚焦于一个非常具体且高频的需求如何审计某个特定数据库账号在Azure Synapse Analytics中的所有操作记录。无论是为了安全合规、故障排查还是单纯的权限复核这都是数据工程师和运维人员必须掌握的技能。你会发现用KQL来做这件事不仅高效而且能挖掘出许多隐藏在简单操作背后的深层信息。2. 审计基石理解Azure Synapse Analytics的日志架构与启用在开始写查询之前我们必须先理解数据从哪里来。Azure Synapse Analytics专指专用SQL池即以前的Azure SQL DW的审计日志并非默认开启也并非存储在数据库内部。它的核心机制是诊断设置Diagnostic Settings。2.1 诊断日志审计数据的源头Azure Synapse Analytics工作区包含专用SQL池会生成多种类型的日志和指标。对于我们审计数据库操作这个目标最关键的一类日志就是SQLSecurityAuditEvents。这类日志记录了所有与SQL安全相关的事件主要包括登录成功/失败SQL批处理Batch的执行这是我们审计操作的核心权限变更GRANT, DENY, REVOKE数据库对象的创建、修改、删除这些日志事件在生成后可以被路由到不同的目的地最常用于分析和长期存储的目的地就是Log Analytics工作区。Log Analytics工作区是Azure Monitor的一部分它使用基于Kusto的引擎来存储和查询日志数据。2.2 配置步骤开启审计并指向Log Analytics如果你的Synapse工作区还没有开启审计你需要进行以下配置。这个过程通常在Azure门户完成是一次性的设置创建或选定Log Analytics工作区在Azure门户中你需要先有一个Log Analytics工作区。如果是为了审计新建的建议取一个易于识别的名字如law-synapse-audit-prod。配置诊断设置导航到你的Azure Synapse Analytics工作区资源。在左侧菜单的“监控”部分找到“诊断设置”。点击“ 添加诊断设置”。在设置页面中诊断设置名称例如SendAuditToLogAnalytics。类别详情勾选SQLSecurityAuditEvents。这是必须勾选的其他日志类别如请求、SQL请求可能对性能分析有用但非审计必需。目标详细信息选择“发送到Log Analytics工作区”然后在下拉列表中选择你创建或指定的工作区。点击“保存”。注意启用诊断设置并开始流式传输日志后数据出现在Log Analytics中会有几分钟的延迟通常5-10分钟。此外向Log Analytics发送数据会产生相应的数据引入和保留费用在规划时需要根据日志量评估成本。完成这个配置后所有在专用SQL池上发生的安全审计事件都会自动、持续地流入指定的Log Analytics工作区中的特定表里。我们的KQL查询舞台就此搭建完毕。2.3 目标数据表AzureDiagnostics还是SynapseSQLLogs这里有一个关键的细节需要注意。根据Azure的更新和资源创建方式审计日志可能出现在两个不同的表中AzureDiagnostics这是一个通用的诊断日志表许多Azure服务的日志都会汇集于此。资源类型ResourceType为SQLDATABASES且类别Category为SQLSecurityAuditEvents的记录就是我们要找的。这是较早期或通过某些方式创建的资源常见的路径。SynapseSQLLogs这是为Azure Synapse Analytics的SQL相关日志量身定制的专用表结构更清晰。如果能看到这个表通常优先使用它。在我们的查询中需要先确认日志存在于哪个表。可以通过一个简单的探测查询来确认// 探测 SynapseSQLLogs 表 SynapseSQLLogs | where Category SQLSecurityAuditEvents | take 1 // 探测 AzureDiagnostics 表 AzureDiagnostics | where ResourceType SQLDATABASES and Category SQLSecurityAuditEvents | take 1哪个查询能返回结果就说明审计日志流向了哪个表。下文的示例将主要使用SynapseSQLLogs因为它更直观。如果您的环境是AzureDiagnostics只需替换表名并调整where条件即可核心KQL逻辑完全一致。3. KQL核心实战定位与解析特定账号的操作流水假设我们需要审计的数据库账号是app_user。我们的目标是从海量日志中精准筛选出与该账号相关的所有操作并以清晰、可读的方式呈现。3.1 基础查询筛选与关键字段提取首先我们构建一个最基础的查询获取app_user的所有安全审计事件。SynapseSQLLogs | where Category SQLSecurityAuditEvents | where SessionServerPrincipalName contains app_user // 包含匹配避免因域名等前缀导致遗漏 | project TimeGenerated, SessionServerPrincipalName, ServerPrincipalName, DatabaseName, Statement, Succeeded, ClientIp, ApplicationName | order by TimeGenerated desc这个查询做了以下几件事where Category SQLSecurityAuditEvents过滤出安全审计事件。where SessionServerPrincipalName contains app_user在SessionServerPrincipalName字段中查找包含app_user的记录。这是登录时使用的账号名是关联操作最可靠的字段之一。使用contains而非是为了兼容可能带域名的账号如domain\app_user。project选择我们需要关注的字段。这是提高查询效率和可读性的关键步骤。TimeGenerated操作发生的时间UTC。SessionServerPrincipalName发起会话的登录名。ServerPrincipalName语句执行上下文中的用户名在EXECUTE AS等场景下可能与登录名不同。DatabaseName操作发生的数据库。Statement执行的SQL语句文本这是审计的核心内容。Succeeded操作是否成功True/False。审计失败登录尝试非常重要。ClientIp发起连接的客户端IP地址。ApplicationName客户端应用程序名称如SSMS、Power BI、自定义应用。order by TimeGenerated desc按时间倒序排列最新的操作在最前面。3.2 深度过滤精准匹配与上下文还原基础查询可能带回很多结果包括其他包含“app_user”字符串的账号虽然概率低。我们可以更精确并丰富查询维度。场景一精确审计app_user账号的所有DML操作INSERT, UPDATE, DELETE, SELECTSynapseSQLLogs | where Category SQLSecurityAuditEvents | where SessionServerPrincipalName has app_user // has 运算符用于全字匹配比 contains 更精确 | where Statement has_any (INSERT, UPDATE, DELETE) or Statement startswith SELECT // 过滤DML语句 | extend StatementSummary substring(Statement, 0, 200) // 只截取语句前200字符便于预览 | project TimeGenerated, SessionServerPrincipalName, DatabaseName, StatementSummary, Succeeded, ClientIp, ApplicationName | order by TimeGenerated desc这里引入了has运算符进行更精确的匹配并使用has_any和startswith来筛选特定的SQL操作类型。extend创建了新列StatementSummary因为完整的Statement可能非常长在结果预览时截取部分内容更友好。场景二审计特定时间段内针对某张关键表如dbo.Sales的所有操作let targetUser app_user; let targetTable Sales; SynapseSQLLogs | where Category SQLSecurityAuditEvents | where TimeGenerated between (datetime(2023-10-27) .. datetime(2023-10-28)) // 指定时间范围 | where SessionServerPrincipalName has targetUser | where Statement contains targetTable // 语句中包含目标表名 | project TimeGenerated, SessionServerPrincipalName, DatabaseName, Statement, ClientIp, ApplicationName | order by TimeGenerated asc // 按时间正序排列方便看操作序列这个查询使用了KQL的let语句定义变量使查询更清晰、易于修改。between运算符用于限定时间范围这对于追溯某个时间段内的操作至关重要。按时间正序asc排列可以像看剧本一样还原操作序列。3.3 聚合分析与洞察不止于列表KQL的强大之处在于其聚合分析能力。我们不仅能列出操作还能生成洞察。分析一统计app_user账号每日执行各类操作的数量SynapseSQLLogs | where Category SQLSecurityAuditEvents | where SessionServerPrincipalName has app_user | extend OperationType case( Statement has INSERT, INSERT, Statement has UPDATE, UPDATE, Statement has DELETE, DELETE, Statement startswith SELECT, SELECT, OTHER // 其他类型操作 ) | summarize OperationCount count() by bin(TimeGenerated, 1d), OperationType | order by TimeGenerated desc, OperationType这个查询使用extend配合case()函数将原始的Statement文本分类成INSERT、UPDATE、DELETE、SELECT、OTHER等操作类型。然后使用summarize和count()按天bin(TimeGenerated, 1d)和操作类型进行聚合计数。结果是一张清晰的统计表可以快速了解该账号的活动模式。分析二找出app_user从非常用IP或应用发起的敏感操作如DROP, ALTERlet commonIPs dynamic([10.0.1.100, 10.0.1.101]); // 定义常用IP白名单 let commonApps dynamic([Microsoft SQL Server Management Studio, PowerBI]); // 定义常用应用白名单 SynapseSQLLogs | where Category SQLSecurityAuditEvents | where SessionServerPrincipalName has app_user | where Statement has_any (DROP, ALTER TABLE, TRUNCATE TABLE) // 敏感操作 | where (ClientIp !in (commonIPs)) or (ApplicationName !in (commonApps)) // 不在白名单内 | project TimeGenerated, SessionServerPrincipalName, Statement, ClientIp, ApplicationName, DatabaseName | order by TimeGenerated desc这是一个安全审计的典型用例。通过定义“正常”行为基线常用IP、常用应用利用KQL的!in不在集合内运算符可以快速筛选出异常或高风险的敏感操作记录用于安全告警或深入调查。4. 高级排查与避坑指南从日志到真相有了查询能力但在真实的故障排查中直接套用模板往往不够。以下是我在实际工作中总结的几个关键点和常见“坑”。4.1 字段辨析SessionServerPrincipalNamevsServerPrincipalName这是最容易混淆的一对字段理解错误可能导致审计遗漏。SessionServerPrincipalName登录名Login Name。用户连接SQL池时使用的身份。例如你用app_user这个登录名连接服务器这个字段就是app_user。绝大多数情况下审计应该基于这个字段。ServerPrincipalName执行上下文中的用户名。在使用了EXECUTE AS USER ‘some_user’或EXECUTE AS LOGIN ‘some_login’的存储过程或动态SQL内部这个字段会变成被模拟的用户而SessionServerPrincipalName仍然是原始的登录名。实战案例有一次排查数据删除问题我们用登录名过滤一无所获。后来发现操作是在一个存储过程中执行的该存储过程使用了EXECUTE AS OWNER。最终在日志中SessionServerPrincipalName是调用存储过程的应用程序账号而ServerPrincipalName是存储过程的所有者一个高权限账号。因此在审计存储过程调用等复杂场景时需要同时关注这两个字段。4.2 语句截断与参数化查询审计日志中的Statement字段可能被截断。对于非常长的SQL批处理你可能看不到完整的语句。这时需要结合其他字段判断。 另外应用程序使用参数化查询如SELECT * FROM t WHERE id id时日志中记录的是带参数的语句而不是具体的值。这保护了敏感数据但也意味着你无法直接从日志看到操作的具体数据内容。排查时需要结合应用程序日志或数据库时间点还原功能。4.3 时间范围与性能优化审计日志量可能非常庞大。一个不加时间范围限制的全表扫描查询可能会超时或消耗极高的查询资源。最佳实践始终在查询开始时使用时间过滤器。Log Analytics默认会利用时间索引。// 好的查询 SynapseSQLLogs | where TimeGenerated ago(7d) // 只看最近7天 | where Category SQLSecurityAuditEvents ... // 避免的查询性能差 SynapseSQLLogs | where Category SQLSecurityAuditEvents | where TimeGenerated ago(7d) // 时间过滤应尽量前置 ...ago()函数非常方便如ago(1h)、ago(7d)。对于长期审计分析可以结合bin()函数进行分时段聚合避免直接查询原始海量数据。4.4 失败操作审计被忽略的安全盲区我们通常关注成功的操作但失败的操作Succeeded False同样重要尤其是登录失败和权限错误。// 监控 app_user 近期的所有失败操作 SynapseSQLLogs | where TimeGenerated ago(1d) | where Category SQLSecurityAuditEvents | where SessionServerPrincipalName has app_user | where Succeeded False | project TimeGenerated, SessionServerPrincipalName, ErrorCode, Statement, ClientIp | order by TimeGenerated desc频繁的登录失败可能意味着密码爆破尝试。特定的权限错误如The SELECT permission was denied可能表明应用程序的权限配置有问题或者有异常访问企图。将这些查询保存并定期检查是安全运营的基础。5. 构建持续监控与自动化审计方案手动查询只能应对事后排查。一个成熟的运维体系需要将审计自动化。5.1 保存查询与仪表板在Log Analytics中你可以将上面任何有用的查询保存。保存的查询可以快速复用也可以被固定到Azure仪表板上。例如创建一个名为“关键账号操作监控”的仪表板磁贴显示app_user过去24小时的操作数量统计、失败操作列表、敏感操作列表等。这样每天打开仪表板就能一目了然。5.2 日志告警实时响应风险操作这是自动化审计的核心。我们可以基于KQL查询创建日志告警规则。场景当app_user账号执行DROP TABLE或TRUNCATE TABLE操作时立即触发告警。在Log Analytics中使用类似下面的查询SynapseSQLLogs | where TimeGenerated ago(5m) // 告警规则通常评估最近5-15分钟的数据 | where Category SQLSecurityAuditEvents | where SessionServerPrincipalName has app_user | where Statement has_any (DROP TABLE, TRUNCATE TABLE) | count点击“新建警报规则”。配置逻辑当查询结果“计数”大于0时触发。配置操作组触发后可以发送邮件、短信、调用Webhook如触发Azure Logic App运行审批流程、或在Teams/Slack中发送通知甚至启动Azure自动化Runbook来执行临时性的安全加固脚本。通过告警审计从事后追溯变成了事中响应极大地提升了安全水位。5.3 定期合规报告对于合规要求如SOX, GDPR可能需要定期出具审计报告。你可以利用Azure 数据资源管理器ADX的连续导出功能或Logic Apps定期如每周运行一个汇总KQL查询将app_user账号的所有关键操作如数据修改、权限变更汇总并自动发送到指定的存储账户或生成邮件报告。例如一个每周运行的报告查询可能长这样SynapseSQLLogs | where TimeGenerated between (startofweek(ago(7d)) .. endofweek(ago(1d))) // 上周整周数据 | where Category SQLSecurityAuditEvents | where SessionServerPrincipalName has app_user | where Statement has_any (INSERT, UPDATE, DELETE, GRANT, REVOKE, CREATE, ALTER, DROP) | summarize StartTime min(TimeGenerated), EndTime max(TimeGenerated), Operations count(), DistinctTablesApprox dcountif(Statement, Statement contains FROM or Statement contains INTO) // 近似统计涉及的表 by SessionServerPrincipalName, DatabaseName | order by DatabaseName从被动地“救火”排查到主动地监控仪表板再到实时的告警响应和自动化的合规报告KQL赋予我们的能力是层层递进的。它不仅仅是一个查询工具更是构建云原生数据平台可观测性与安全体系的核心组件。掌握它意味着你能真正“看见”数据平台内部发生的每一件事并为数据的安全与稳定保驾护航。

相关新闻

springboot员工KPI考核与晋升系统12888-计算机课程设计/毕业设计

springboot员工KPI考核与晋升系统12888-计算机课程设计/毕业设计

前言 📌博主介绍:一线全栈工程师,毕设实战引路人。技术栈覆盖Java、Python、C#、PHP、Node.js及UniApp跨端开发,擅长多语言项目落地与架构设计。持续分享毕设源码、开题报告、技术选型心得与职场踩坑经验。用工程化思维写代码&am…

2026/10/16 6:39:43 阅读更多 →
回形取数算法:矩阵螺旋遍历的实现与应用

回形取数算法:矩阵螺旋遍历的实现与应用

1. 回形取数问题概述回形取数是一种经典的矩阵遍历算法,要求按照从外到内顺时针方向依次访问矩阵中的每个元素。这个问题在东华OJ的进阶题库中出现,主要考察编程者对二维数组操作和边界控制的能力。在实际应用中,类似算法常用于图像处理中的螺…

2026/10/15 22:09:48 阅读更多 →
北京网站建设学校揭秘:普通人如何低成本逆袭互联网高薪赛道

北京网站建设学校揭秘:普通人如何低成本逆袭互联网高薪赛道

说实话,看到这个话题,我心里其实是有点复杂的。在这个互联网信息爆炸的时代,各种“速成班”、“零基础逆袭”、“月入过万不是梦”的广告满天飞,让人真假难辨。很多人问我,北京网站建设学校到底靠不靠谱?我想说,没有绝对的靠谱与不靠谱,只有适不适合你,以及你是否愿意…

2026/10/9 23:53:37 阅读更多 →

最新新闻

Flask+Redis+MySQL打造电商购书平台:抽奖与积分系统实战解析

Flask+Redis+MySQL打造电商购书平台:抽奖与积分系统实战解析

如果你搜Python练手项目,排名靠前的大概率是图书管理系统、爬虫、记账本这类。但真正能帮你把电商知识串起来的项目,至少要包含商品、订单、支付、库存,而线上购书平台如果再加上抽奖和积分兑换,基本就是把运营玩法也补齐了。我前…

2026/10/16 7:58:16 阅读更多 →
AI产品经理的决策框架:从Agent落地看人机协同设计

AI产品经理的决策框架:从Agent落地看人机协同设计

1. 这不是技术课,是AI产品决策现场的复盘笔记做了几个 Agent 项目后,我发现:真正拉开 AI 产品经理差距的,不是技术——这句话我是在凌晨三点改完第三版 workflow 编排逻辑、盯着日志里反复失败的 tool calling 调用链发呆时写下的…

2026/10/16 7:58:16 阅读更多 →
毕业论文AI率41%到9%:降AI的48小时自救与四步拆骨法

毕业论文AI率41%到9%:降AI的48小时自救与四步拆骨法

说实话,我从来没觉得“AI率”三个字会以那种方式砸在我脸上。周一上午十点,我正坐在实验室改论文的参考文献格式,手机屏幕弹出一条消息,是导师转发的学院系统检测报告截图。我那篇熬了快一个月的毕业论文初稿,疑似AI生…

2026/10/16 7:58:16 阅读更多 →
Python学习笔记:从虚拟环境到调试的完整成长路径

Python学习笔记:从虚拟环境到调试的完整成长路径

每次有人问我“Python学到什么程度算入门”,我的回答从来都是:去翻你自己的Python学习笔记。如果笔记里全是复制粘贴的代码,说明还在抄作业阶段;如果里面有报错记录、踩坑复盘、以及你自己写下的注释,那才算真正开始会…

2026/10/16 7:58:16 阅读更多 →
迭代学习控制开源代码:让重复作业系统一次比一次精准

迭代学习控制开源代码:让重复作业系统一次比一次精准

简介:迭代学习控制(ILC)是一类面向重复性任务的控制策略,核心思想是通过多次迭代修正控制输入,逐步逼近期望输出,在机器人、自动化生产线、航空航天等领域均有广泛应用。这份开源代码以单个MATLAB的m文件呈…

2026/10/16 7:58:16 阅读更多 →
nvidia-smi命令找不到?从驱动到容器彻底排查与修复指南

nvidia-smi命令找不到?从驱动到容器彻底排查与修复指南

“nvidia-smi: command not found”大概是 Linux 装显卡驱动时最经典、也最让人摸不着头脑的报错。我第一次遇到是在一台刚装完系统的服务器上,当时还以为是显卡坏了,折腾半天才发现只是驱动没装上。后来搞多了就明白,这个报错本身不复杂&…

2026/10/16 7:57:16 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →