learn.lianglianglee.com/文章/MySQL 日志详解.md.html
2022-08-14 03:40:33 +08:00

1123 lines
69 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>MySQL 日志详解.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/文章/AQS 万字图文全面解析.md.html">AQS 万字图文全面解析</a>
</li>
<li>
<a href="/文章/Docker 镜像构建原理及源码分析.md.html">Docker 镜像构建原理及源码分析</a>
</li>
<li>
<a href="/文章/ElasticSearch 小白从入门到精通.md.html">ElasticSearch 小白从入门到精通</a>
</li>
<li>
<a href="/文章/JVM CPU Profiler技术原理及源码深度解析.md.html">JVM CPU Profiler技术原理及源码深度解析</a>
</li>
<li>
<a href="/文章/JVM 垃圾收集器.md.html">JVM 垃圾收集器</a>
</li>
<li>
<a href="/文章/JVM 面试的 30 个知识点.md.html">JVM 面试的 30 个知识点</a>
</li>
<li>
<a href="/文章/Java IO 体系、线程模型大总结.md.html">Java IO 体系、线程模型大总结</a>
</li>
<li>
<a href="/文章/Java NIO浅析.md.html">Java NIO浅析</a>
</li>
<li>
<a href="/文章/Java 面试题集锦(网络篇).md.html">Java 面试题集锦(网络篇)</a>
</li>
<li>
<a href="/文章/Java-直接内存 DirectMemory 详解.md.html">Java-直接内存 DirectMemory 详解</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md.html">Java中9种常见的CMS GC问题分析与解决</a>
</li>
<li>
<a href="/文章/Java中9种常见的CMS GC问题分析与解决.md.html">Java中9种常见的CMS GC问题分析与解决</a>
</li>
<li>
<a href="/文章/Java中的SPI.md.html">Java中的SPI</a>
</li>
<li>
<a href="/文章/Java中的ThreadLocal.md.html">Java中的ThreadLocal</a>
</li>
<li>
<a href="/文章/Java线程池实现原理及其在美团业务中的实践.md.html">Java线程池实现原理及其在美团业务中的实践</a>
</li>
<li>
<a href="/文章/Java魔法类Unsafe应用解析.md.html">Java魔法类Unsafe应用解析</a>
</li>
<li>
<a href="/文章/Kafka 源码阅读笔记.md.html">Kafka 源码阅读笔记</a>
</li>
<li>
<a href="/文章/Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理.md.html">Kafka、ActiveMQ、RabbitMQ、RocketMQ 区别以及高可用原理</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB Buffer Pool.md.html">MySQL · 引擎特性 · InnoDB Buffer Pool</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB IO子系统.md.html">MySQL · 引擎特性 · InnoDB IO子系统</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 事务系统.md.html">MySQL · 引擎特性 · InnoDB 事务系统</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 同步机制.md.html">MySQL · 引擎特性 · InnoDB 同步机制</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB 数据页解析.md.html">MySQL · 引擎特性 · InnoDB 数据页解析</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · InnoDB崩溃恢复.md.html">MySQL · 引擎特性 · InnoDB崩溃恢复</a>
</li>
<li>
<a href="/文章/MySQL · 引擎特性 · 临时表那些事儿.md.html">MySQL · 引擎特性 · 临时表那些事儿</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 半同步复制.md.html">MySQL 主从复制 半同步复制</a>
</li>
<li>
<a href="/文章/MySQL 主从复制 基于GTID复制.md.html">MySQL 主从复制 基于GTID复制</a>
</li>
<li>
<a href="/文章/MySQL 主从复制.md.html">MySQL 主从复制</a>
</li>
<li>
<a href="/文章/MySQL 事务日志(redo log和undo log).md.html">MySQL 事务日志(redo log和undo log)</a>
</li>
<li>
<a href="/文章/MySQL 亿级别数据迁移实战代码分享.md.html">MySQL 亿级别数据迁移实战代码分享</a>
</li>
<li>
<a href="/文章/MySQL 从一条数据说起-InnoDB行存储数据结构.md.html">MySQL 从一条数据说起-InnoDB行存储数据结构</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:事务和锁的面纱.md.html">MySQL 地基基础:事务和锁的面纱</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据字典.md.html">MySQL 地基基础:数据字典</a>
</li>
<li>
<a href="/文章/MySQL 地基基础:数据库字符集.md.html">MySQL 地基基础:数据库字符集</a>
</li>
<li>
<a href="/文章/MySQL 性能优化:碎片整理.md.html">MySQL 性能优化:碎片整理</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?.md.html">MySQL 故障诊断:一个 ALTER TALBE 执行了很久,你慌不慌?</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:如何在日志中轻松定位大事务.md.html">MySQL 故障诊断:如何在日志中轻松定位大事务</a>
</li>
<li>
<a href="/文章/MySQL 故障诊断:教你快速定位加锁的 SQL.md.html">MySQL 故障诊断:教你快速定位加锁的 SQL</a>
</li>
<li>
<a class="current-tab" href="/文章/MySQL 日志详解.md.html">MySQL 日志详解</a>
</li>
<li>
<a href="/文章/MySQL 的半同步是什么?.md.html">MySQL 的半同步是什么?</a>
</li>
<li>
<a href="/文章/MySQL中的事务和MVCC.md.html">MySQL中的事务和MVCC</a>
</li>
<li>
<a href="/文章/MySQL事务_事务隔离级别详解.md.html">MySQL事务_事务隔离级别详解</a>
</li>
<li>
<a href="/文章/MySQL优化优化 select count().md.html">MySQL优化优化 select count()</a>
</li>
<li>
<a href="/文章/MySQL共享锁、排他锁、悲观锁、乐观锁.md.html">MySQL共享锁、排他锁、悲观锁、乐观锁</a>
</li>
<li>
<a href="/文章/MySQL的MVCC多版本并发控制.md.html">MySQL的MVCC多版本并发控制</a>
</li>
<li>
<a href="/文章/QingStor 对象存储架构设计及最佳实践.md.html">QingStor 对象存储架构设计及最佳实践</a>
</li>
<li>
<a href="/文章/RocketMQ 面试题集锦.md.html">RocketMQ 面试题集锦</a>
</li>
<li>
<a href="/文章/SnowFlake 雪花算法生成分布式 ID.md.html">SnowFlake 雪花算法生成分布式 ID</a>
</li>
<li>
<a href="/文章/Spring Boot 2.x 结合 k8s 实现分布式微服务架构.md.html">Spring Boot 2.x 结合 k8s 实现分布式微服务架构</a>
</li>
<li>
<a href="/文章/Spring Boot 教程:如何开发一个 starter.md.html">Spring Boot 教程:如何开发一个 starter</a>
</li>
<li>
<a href="/文章/Spring MVC 原理.md.html">Spring MVC 原理</a>
</li>
<li>
<a href="/文章/Spring MyBatis和Spring整合的奥秘.md.html">Spring MyBatis和Spring整合的奥秘</a>
</li>
<li>
<a href="/文章/Spring 帮助你更好的理解Spring循环依赖.md.html">Spring 帮助你更好的理解Spring循环依赖</a>
</li>
<li>
<a href="/文章/Spring 循环依赖及解决方式.md.html">Spring 循环依赖及解决方式</a>
</li>
<li>
<a href="/文章/Spring中眼花缭乱的BeanDefinition.md.html">Spring中眼花缭乱的BeanDefinition</a>
</li>
<li>
<a href="/文章/Vert.x 基础入门.md.html">Vert.x 基础入门</a>
</li>
<li>
<a href="/文章/eBay 的 Elasticsearch 性能调优实践.md.html">eBay 的 Elasticsearch 性能调优实践</a>
</li>
<li>
<a href="/文章/不可不说的Java“锁”事.md.html">不可不说的Java“锁”事</a>
</li>
<li>
<a href="/文章/互联网并发限流实战.md.html">互联网并发限流实战</a>
</li>
<li>
<a href="/文章/从ReentrantLock的实现看AQS的原理及应用.md.html">从ReentrantLock的实现看AQS的原理及应用</a>
</li>
<li>
<a href="/文章/从SpringCloud开始聊微服务架构.md.html">从SpringCloud开始聊微服务架构</a>
</li>
<li>
<a href="/文章/全面了解 JDK 线程池实现原理.md.html">全面了解 JDK 线程池实现原理</a>
</li>
<li>
<a href="/文章/分布式一致性理论与算法.md.html">分布式一致性理论与算法</a>
</li>
<li>
<a href="/文章/分布式一致性算法 Raft.md.html">分布式一致性算法 Raft</a>
</li>
<li>
<a href="/文章/分布式唯一 ID 解析.md.html">分布式唯一 ID 解析</a>
</li>
<li>
<a href="/文章/分布式链路追踪:集群管理设计.md.html">分布式链路追踪:集群管理设计</a>
</li>
<li>
<a href="/文章/动态代理种类及原理,你知道多少?.md.html">动态代理种类及原理,你知道多少?</a>
</li>
<li>
<a href="/文章/响应式架构与 RxJava 在有赞零售的实践.md.html">响应式架构与 RxJava 在有赞零售的实践</a>
</li>
<li>
<a href="/文章/大数据算法——布隆过滤器.md.html">大数据算法——布隆过滤器</a>
</li>
<li>
<a href="/文章/如何优雅地记录操作日志?.md.html">如何优雅地记录操作日志?</a>
</li>
<li>
<a href="/文章/如何设计一个亿级消息量的 IM 系统.md.html">如何设计一个亿级消息量的 IM 系统</a>
</li>
<li>
<a href="/文章/异步网络模型.md.html">异步网络模型</a>
</li>
<li>
<a href="/文章/当我们在讨论CQRS时我们在讨论些神马.md.html">当我们在讨论CQRS时我们在讨论些神马</a>
</li>
<li>
<a href="/文章/彻底理解 MySQL 的索引机制.md.html">彻底理解 MySQL 的索引机制</a>
</li>
<li>
<a href="/文章/最全的 116 道 Redis 面试题解答.md.html">最全的 116 道 Redis 面试题解答</a>
</li>
<li>
<a href="/文章/有赞权限系统(SAM).md.html">有赞权限系统(SAM)</a>
</li>
<li>
<a href="/文章/有赞零售中台建设方法的探索与实践.md.html">有赞零售中台建设方法的探索与实践</a>
</li>
<li>
<a href="/文章/服务注册与发现原理剖析Eureka、Zookeeper、Nacos.md.html">服务注册与发现原理剖析Eureka、Zookeeper、Nacos</a>
</li>
<li>
<a href="/文章/深入浅出Cache.md.html">深入浅出Cache</a>
</li>
<li>
<a href="/文章/深入理解 MySQL 底层实现.md.html">深入理解 MySQL 底层实现</a>
</li>
<li>
<a href="/文章/漫画讲解 git rebase VS git merge.md.html">漫画讲解 git rebase VS git merge</a>
</li>
<li>
<a href="/文章/生成浏览器唯一稳定 ID 的探索.md.html">生成浏览器唯一稳定 ID 的探索</a>
</li>
<li>
<a href="/文章/缓存 如何保证缓存与数据库的双写一致性?.md.html">缓存 如何保证缓存与数据库的双写一致性?</a>
</li>
<li>
<a href="/文章/网易严选怎么做全链路监控的?.md.html">网易严选怎么做全链路监控的?</a>
</li>
<li>
<a href="/文章/美团万亿级 KV 存储架构与实践.md.html">美团万亿级 KV 存储架构与实践</a>
</li>
<li>
<a href="/文章/美团点评Kubernetes集群管理实践.md.html">美团点评Kubernetes集群管理实践</a>
</li>
<li>
<a href="/文章/美团百亿规模API网关服务Shepherd的设计与实现.md.html">美团百亿规模API网关服务Shepherd的设计与实现</a>
</li>
<li>
<a href="/文章/解读《阿里巴巴 Java 开发手册》背后的思考.md.html">解读《阿里巴巴 Java 开发手册》背后的思考</a>
</li>
<li>
<a href="/文章/认识 MySQL 和 Redis 的数据一致性问题.md.html">认识 MySQL 和 Redis 的数据一致性问题</a>
</li>
<li>
<a href="/文章/进阶Dockerfile 高阶使用指南及镜像优化.md.html">进阶Dockerfile 高阶使用指南及镜像优化</a>
</li>
<li>
<a href="/文章/铁总在用的高性能分布式缓存计算框架 Geode.md.html">铁总在用的高性能分布式缓存计算框架 Geode</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html">阿里云PolarDB及其共享存储PolarFS技术实现分析</a>
</li>
<li>
<a href="/文章/阿里云PolarDB及其共享存储PolarFS技术实现分析.md.html">阿里云PolarDB及其共享存储PolarFS技术实现分析</a>
</li>
<li>
<a href="/文章/面试最常被问的 Java 后端题.md.html">面试最常被问的 Java 后端题</a>
</li>
<li>
<a href="/文章/领域驱动设计在互联网业务开发中的实践.md.html">领域驱动设计在互联网业务开发中的实践</a>
</li>
<li>
<a href="/文章/领域驱动设计的菱形对称架构.md.html">领域驱动设计的菱形对称架构</a>
</li>
<li>
<a href="/文章/高效构建 Docker 镜像的最佳实践.md.html">高效构建 Docker 镜像的最佳实践</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>MySQL 日志详解</h1>
<p>官方手册:<a href="https://dev.mysql.com/doc/refman/5.7/en/server-logs.html">https://dev.mysql.com/doc/refman/5.7/en/server-logs.html</a></p>
<p>不管是哪个数据库产品一定会有日志文件。在MariaDB/MySQL中主要有5种日志文件
1.错误日志(error log)记录mysql服务的启停时正确和错误的信息还记录启动、停止、运行过程中的错误信息。
2.查询日志(general log):记录建立的客户端连接和执行的语句。
3.二进制日志(bin log):记录所有更改数据的语句,可用于数据复制。
4.慢查询日志(slow log)记录所有执行时间超过long_query_time的所有查询或不使用索引的查询。
5.中继日志(relay log):主从复制时使用的日志。</p>
<p>除了这5种日志在需要的时候还会创建DDL日志。本文暂先讨论错误日志、一般查询日志、慢查询日志和二进制日志中继日志和主从复制有关将在复制的章节中介绍。下一篇文章将介绍innodb事务日志<a href="https://www.cnblogs.com/f-ck-need-u/p/9010872.html">MySQL的事务日志</a></p>
<h1>1.日志刷新操作</h1>
<p>以下操作会刷新日志文件,刷新日志文件时会关闭旧的日志文件并重新打开日志文件。对于有些日志类型,如二进制日志,刷新日志会滚动日志文件,而不仅仅是关闭并重新打开。</p>
<pre><code>mysql&gt; FLUSH LOGS;
shell&gt; mysqladmin flush-logs
shell&gt; mysqladmin refresh
</code></pre>
<h1>2.错误日志</h1>
<p>错误日志是最重要的日志之一它记录了MariaDB/MySQL服务启动和停止正确和错误的信息还记录了mysqld实例运行过程中发生的错误事件信息。</p>
<p>可以使用&quot; --log-error=[file_name] &quot;来指定mysqld记录的错误日志文件如果没有指定file_name则默认的错误日志文件为datadir目录下的 <code>hostname</code>.err hostname表示当前的主机名。</p>
<p>也可以在MariaDB/MySQL配置文件中的mysqld配置部分使用log-error指定错误日志的路径。</p>
<p>如果不知道错误日志的位置可以查看变量log_error来查看。</p>
<pre><code>mysql&gt; show variables like 'log_error';
+---------------+----------------------------------------+
| Variable_name | Value |
+---------------+----------------------------------------+
| log_error | /var/lib/mysql/node1.longshuai.com.err |
+---------------+----------------------------------------+
</code></pre>
<p>在MySQL 5.5.7之前,刷新日志操作(如flush logs)会备份旧的错误日志(以_old结尾)并创建一个新的错误日志文件并打开在MySQL 5.5.7之后,执行刷新日志的操作时,错误日志会关闭并重新打开,如果错误日志不存在,则会先创建。</p>
<p>在MariaDB/MySQL正在运行状态下删除错误日志后不会自动创建错误日志只有在刷新日志的时候才会创建一个新的错误日志文件。</p>
<p>以下是MySQL 5.6.35启动的日志信息。</p>
<pre><code>2017-03-29 01:15:14 2362 [Note] Plugin 'FEDERATED' is disabled.
2017-03-29 01:15:14 2362 [Note] InnoDB: Using atomics to ref count buffer pool pages
2017-03-29 01:15:14 2362 [Note] InnoDB: The InnoDB memory heap is disabled
2017-03-29 01:15:14 2362 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2017-03-29 01:15:14 2362 [Note] InnoDB: Memory barrier is not used
2017-03-29 01:15:14 2362 [Note] InnoDB: Compressed tables use zlib 1.2.3
2017-03-29 01:15:14 2362 [Note] InnoDB: Using Linux native AIO
2017-03-29 01:15:14 2362 [Note] InnoDB: Using CPU crc32 instructions
2017-03-29 01:15:14 2362 [Note] InnoDB: Initializing buffer pool, size = 128.0M
2017-03-29 01:15:14 2362 [Note] InnoDB: Completed initialization of buffer pool
2017-03-29 01:15:14 2362 [Note] InnoDB: Highest supported file format is Barracuda.
2017-03-29 01:15:14 2362 [Note] InnoDB: 128 rollback segment(s) are active.
2017-03-29 01:15:14 2362 [Note] InnoDB: Waiting for purge to start
2017-03-29 01:15:14 2362 [Note] InnoDB: 5.6.35 started; log sequence number 3911610
2017-03-29 01:15:14 2362 [Note] Server hostname (bind-address): '*'; port: 3306
2017-03-29 01:15:14 2362 [Note] IPv6 is available.
2017-03-29 01:15:14 2362 [Note] - '::' resolves to '::';
2017-03-29 01:15:14 2362 [Note] Server socket created on IP: '::'.
2017-03-29 01:15:14 2362 [Warning] 'proxies_priv' entry '@ <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="72001d1d06320a07170a1b5c1e1d1c15011a07131b5c111d1f">[email&#160;protected]</a>' ignored in --skip-name-resolve mode.
2017-03-29 01:15:14 2362 [Note] Event Scheduler: Loaded 0 events
2017-03-29 01:15:14 2362 [Note] /usr/local/mysql/bin/mysqld: ready for connections.
Version: '5.6.35' socket: '/mydata/data/mysql.sock' port: 3306 MySQL Community Server (GPL)
</code></pre>
<h1>3.一般查询日志</h1>
<p>查询日志分为一般查询日志和慢查询日志,它们是通过查询是否超出变量 long_query_time 指定时间的值来判定的。在超时时间内完成的查询是一般查询,可以将其记录到一般查询日志中,<strong>但是建议关闭这种日志(默认是关闭的)</strong>,超出时间的查询是慢查询,可以将其记录到慢查询日志中。</p>
<p>使用&quot; --general_log={0|1} &quot;来决定是否启用一般查询日志,使用&quot; --general_log_file=file_name &quot;来指定查询日志的路径。不给定路径时默认的文件名以 <code>hostname</code>.log 命名。</p>
<p>和查询日志有关的变量有:</p>
<pre><code>`long_query_time = 10 ``# 指定慢查询超时时长,超出此时长的属于慢查询,会记录到慢查询日志中``log_output={TABLE|FILE|NONE} ``# 定义一般查询日志和慢查询日志的输出格式不指定时默认为file`
</code></pre>
<p>TABLE表示记录日志到表中FILE表示记录日志到文件中NONE表示不记录日志。只要这里指定为NONE即使开启了一般查询日志和慢查询日志也都不会有任何记录。</p>
<p>和一般查询日志相关的变量有:</p>
<pre><code>`general_log=off ``# 是否启用一般查询日志为全局变量必须在global上修改。``sql_log_off=off ``# 在session级别控制是否启用一般查询日志默认为off即启用``general_log_file=``/mydata/data/hostname``.log ``# 默认是库文件路径下主机名加上.log`
</code></pre>
<p>在MySQL 5.6以前的版本还有一个&quot;log&quot;变量也是决定是否开启一般查询日志的。在5.6版本开始已经废弃了该选项。</p>
<p>默认没有开启一般查询日志,也不建议开启一般查询日志。此处打开该类型的日志,看看是如何记录一般查询日志的。</p>
<p>首先开启一般查询日志。</p>
<pre><code>mysql&gt; set @@global.general_log=1;
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="7705181803370f02120f1e">[email&#160;protected]</a> data]# ll *.log
-rw-rw---- 1 mysql mysql 5423 Mar 20 16:29 mysqld.log
-rw-rw---- 1 mysql mysql 262 Mar 29 09:31 xuexi.log
</code></pre>
<p>执行几个语句。</p>
<pre><code>mysql&gt; select host,user from mysql.user;
mysql&gt; show variables like &quot;%error%&quot;;
mysql&gt; insert into ttt values(233);
mysql&gt; create table tt(id int);
mysql&gt; set @a:=3;
</code></pre>
<p>查看一般查询日志的内容。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e795888893a79f92829f8e">[email&#160;protected]</a> data]# cat xuexi.log
/usr/local/mysql/bin/mysqld, Version: 5.6.35-log (MySQL Community Server (GPL)). started with:
Tcp port: 3306 Unix socket: /mydata/data/mysql.sock
Time Id Command Argument
180421 20:04:41 13 Query select user,host from mysql.user
180421 20:06:06 13 Query show variables like &quot;%error%&quot;
180421 20:07:28 13 Query insert into ttt values(233)
180421 20:11:47 13 Query create table tt(id int)
180421 20:12:29 13 Query set @a:=3
</code></pre>
<p>由此可知一般查询日志查询的不止是select语句几乎所有的语句都会记录。</p>
<h1>4.慢查询日志</h1>
<p>查询超出变量 long_query_time 指定时间值的为慢查询。但是查询获取锁(包括锁等待)的时间不计入查询时间内。</p>
<p>mysql记录慢查询日志是在查询执行完毕且已经完全释放锁之后才记录的因此慢查询日志记录的顺序和执行的SQL查询语句顺序可能会不一致(例如语句1先执行查询速度慢语句2后执行但查询速度快则语句2先记录)。</p>
<p>注意MySQL 5.1之后就支持微秒级的慢查询超时时长对于DBA来说一个查询运行0.5秒和运行0.05秒是非常不同的,前者可能索引使用错误或者走了表扫描,后者可能索引使用正确。</p>
<p>另外,指定的慢查询超时时长表示的是超出这个时间的才算是慢查询,等于这个时间的不会记录。</p>
<p>和慢查询有关的变量:</p>
<pre><code>`long_query_time=10 ``# 指定慢查询超时时长(默认10秒),超出此时长的属于慢查询``log_output={TABLE|FILE|NONE} ``# 定义一般查询日志和慢查询日志的输出格式默认为file``log_slow_queries={``yes``|no} ``# 是否启用慢查询日志,默认不启用``slow_query_log={1|ON|0|OFF} ``# 也是是否启用慢查询日志此变量和log_slow_queries修改一个另一个同时变化``slow_query_log_file=``/mydata/data/hostname-slow``.log ``#默认路径为库文件目录下主机名加上-slow.log``log_queries_not_using_indexes=OFF ``# 查询没有使用索引的时候是否也记入慢查询日志`
</code></pre>
<p>现在启用慢查询日志。</p>
<pre><code>mysql&gt; set @@global.slow_query_log=on;
</code></pre>
<p>因为默认超时时长为10秒所以进行一个10秒的查询。</p>
<pre><code>mysql&gt; select sleep(10);
</code></pre>
<p>查看慢查询日志文件。这里看到虽然sleep了10秒但是最后查询时间超出了847微秒因此这里也记录了该查询。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4b3924243f0b333e2e3322">[email&#160;protected]</a> data]# cat xuexi-slow.log
/usr/local/mysql/bin/mysqld, Version: 5.6.35-log (MySQL Community Server (GPL)). started with:
Tcp port: 3306 Unix socket: /mydata/data/mysql.sock
Time Id Command Argument
# Time: 170329 9:55:58
# <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="104563756250587f6364">[email&#160;protected]</a>: root[root] @ localhost [] Id: 1
# Query_time: 10.000847 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0
use test;
SET timestamp=1490752558;
select sleep(10);
</code></pre>
<p>随着时间的推移慢查询日志文件中的记录可能会变得非常多这对于分析查询来说是非常困难的。好在提供了一个专门归类慢查询日志的工具mysqldumpslow。</p>
<pre><code>`[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="53213c3c27132b26362b3a">[email&#160;protected]</a> data]``# mysqldumpslow --help`` ``-d debug `` ``-``v` `verbose显示详细信息`` ``-t NUM just show the ``top` `n queries仅显示前n条查询`` ``-a don``'t abstract all numbers to N and strings to '``S'归类时不要使用N替换数字S替换字符串`` ``-g PATTERN ``grep``: only consider stmts that include this string通过``grep``来筛选``select``语句。`
</code></pre>
<p>该工具归类的时候,默认会将<strong>同文本但变量值不同的查询语句视为同一类并使用N代替其中的数值变量使用S代替其中的字符串变量</strong>。可以使用-a来禁用这种替换。如</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="55273a3a21152d20302d3c">[email&#160;protected]</a> data]# mysqldumpslow xuexi-slow.log
Reading mysql slow query log from xuexi-slow.log
Count: 1 Time=10.00s (10s) Lock=0.00s (0s) Rows=1.0 (1), root[root]@localhost
select sleep(N)
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6d1f0202192d1518081504">[email&#160;protected]</a> data]# mysqldumpslow -a xuexi-slow.log
Reading mysql slow query log from xuexi-slow.log
Count: 1 Time=10.00s (10s) Lock=0.00s (0s) Rows=1.0 (1), root[root]@localhost
select sleep(10)
</code></pre>
<p>显然这里归类后的结果只是精确到0.01秒的,如果想要显示及其精确的秒数,则使用-d选项启用调试功能。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a5d7cacad1e5ddd0c0ddcc">[email&#160;protected]</a> data]# mysqldumpslow -d xuexi-slow.log
Reading mysql slow query log from xuexi-slow.log
[[/usr/local/mysql/bin/mysqld, Version: 5.6.35-log (MySQL Community Server (GPL)). started with:
Tcp port: 3306 Unix socket: /mydata/data/mysql.sock
Time Id Command Argument
# Time: 170329 9:55:58
# <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="80d5f3e5f2c0c8eff3f4">[email&#160;protected]</a>: root[root] @ localhost [] Id: 1
# Query_time: 10.000847 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0
use test;
SET timestamp=1490752558;
select sleep(10);
]]
&lt;&lt;&gt;&gt;
&lt;&lt;# Time: 170329 9:55:58
# <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="85d0f6e0f7c5cdeaf6f1">[email&#160;protected]</a>: root[root] @ localhost [] Id: 1
# Query_time: 10.000847 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0
use test;
SET timestamp=1490752558;
select sleep(10);
&gt;&gt; at /usr/local/mysql/bin/mysqldumpslow line 97, &lt;&gt; chunk 1.
[[# Time: 170329 9:55:58
# <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="287d5b4d5a6860475b5c">[email&#160;protected]</a>: root[root] @ localhost [] Id: 1
# Query_time: 10.000847 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0
use test;
SET timestamp=1490752558;
select sleep(10);
]]
{{ select sleep(N)}}
Count: 1 Time=10.00s (10s) Lock=0.00s (0s) Rows=1.0 (1), root[root]@localhost
select sleep(N)
</code></pre>
<p>慢查询在SQL语句调优的时候非常有用应该将它启用起来且应该让慢查询阈值尽量小例如1秒甚至低于1秒。就像一天执行上千次的1秒语句和一天执行几次的20秒语句显然更值得去优化这个1秒的语句。</p>
<h1>5.二进制日志</h1>
<h2>5.1 二进制日志文件</h2>
<p>二进制日志包含了<strong>引起或可能引起数据库改变</strong>(如delete语句但没有匹配行)的事件信息但绝不会包括select和show这样的查询语句。语句以&quot;事件&quot;的形式保存,所以包含了时间、事件开始和结束位置等信息。</p>
<p>二进制日志是<strong>以事件形式记录的,不是事务日志****(****但可能是基于事务来记录二进制日志)</strong>不代表它只记录innodb日志myisam表也一样有二进制日志。</p>
<p>对于事务表的操作,二进制日志<strong>只在事务提交的时候一次性写入****(<strong><strong>基于事务的innodb</strong></strong>二进制日志)提交前的每个二进制日志记录都先cache提交时写入</strong></p>
<p>所以,对于事务表来说,一个事务中可能包含多条二进制日志事件,它们会在提交时一次性写入。而对于非事务表的操作,每次执行完语句就直接写入。</p>
<p>MariaDB/MySQL默认没有启动二进制日志要启用二进制日志使用 --log-bin=[on|off|file_name] 选项指定如果没有给定file_name则默认为datadir下的主机名加&quot;-bin&quot;,并在后面跟上一串数字表示日志序列号,如果给定的日志文件中包含了后缀(logname.suffix)将忽略后缀部分。</p>
<p><img src="assets/733013-20180507084125816-1681048114.png" alt="img" /></p>
<p>或者在配置文件中的[mysqld]部分设置log-bin也可以。注意对于mysql 5.7直接启动binlog可能会导致mysql服务启动失败这时需要在配置文件中的mysqld为mysql实例分配server_id。</p>
<pre><code>`[mysqld]``# server_id=1234``log-bin=[on|filename]`
</code></pre>
<p>mysqld还<strong>创建一个二进制日志索引文件</strong>,当二进制日志文件滚动的时候会向该文件中写入对应的信息。所以该文件包含所有使用的二进制日志文件的文件名。默认情况下该文件与二进制日志文件的文件名相同,扩展名为'.index'。要指定该文件的文件名使用 --log-bin-index[=file_name] 选项。当mysqld在运行时不应手动编辑该文件免得mysqld变得混乱。</p>
<p>当重启mysql服务或刷新日志或者达到日志最大值时将滚动二进制日志文件滚动日志时只修改日志文件名的数字序列部分。</p>
<p>二进制日志文件的最大值通过变量 max_binlog_size 设置(默认值为1G)。但由于二进制日志可能是基于事务来记录的(如innodb表类型),而事务是绝对不可能也不应该跨文件记录的,如果正好二进制日志文件达到了最大值但事务还没有提交则不会滚动日志,而是继续增大日志,所以 max_binlog_size 指定的值和实际的二进制日志大小不一定相等。</p>
<p>因为二进制日志文件增长迅速但官方说明因此而损耗的性能小于1%,且二进制目的是为了恢复定点数据库和主从复制,所以出于安全和功能考虑,<strong>极不建议将二进制日志和<strong><strong>datadir</strong></strong>放在同一磁盘上</strong></p>
<h2>5.2 查看二进制日志</h2>
<p>MySQL中查看二进制日志的方法主要有几种。</p>
<p>1.使用mysqlbinlog工具。</p>
<p>2.使用show显示对应的信息。</p>
<pre><code>`SHOW {BINARY | MASTER} LOGS ``# 查看使用了哪些日志文件``SHOW BINLOG EVENTS [IN ``'log_name'``] [FROM pos] ``# 查看日志中进行了哪些操作``SHOW MASTER STATUS ``# 显式主服务器中的二进制日志信息`
</code></pre>
<h3>5.2.1 mysqlbinlog</h3>
<p>二进制日志可以使用mysqlbinlog命令查看。</p>
<pre><code>`mysqlbinlog [option] log-file1 log-file2...`
</code></pre>
<p>以下是常用的几个选项:</p>
<pre><code>`-d,--database=name只查看指定数据库的日志操作``-o,--offset=``#忽略掉日志中的前n个操作命令``-r,--result-``file``=name将输出的日志信息输出到指定的文件中使用重定向也一样可以。``-s,--short-form显示简单格式的日志只记录一些普通的语句会省略掉一些额外的信息如位置信息和时间信息以及基于行的日志。可以用来调试生产环境千万不可使用``--``set``-charset=char_name在输出日志信息到文件中时在文件第一行加上``set` `names char_name``--start-datetime,--stop-datetime指定输出开始时间和结束时间内的所有日志信息``--start-position=``#,--stop-position=#:指定输出开始位置和结束位置内的所有日志信息``-``v``,-vv显示更详细信息基于row的日志默认不会显示出来此时使用-``v``或-vv可以查看`
</code></pre>
<p>在进行测试之前,先对日志进行一次刷新,以方便解释二进制日志的信息。</p>
<pre><code>shell&gt; mysqladmin -uroot -p refresh
</code></pre>
<p>假设现在的日志文件是mysql-bin.000001,里面暂时只有一些初始信息,没有记录任何操作过的记录。</p>
<p>下面是每个二进制日志文件的初始信息。可以看到记录了时间和位置信息(at 4)。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bfcdd0d0cbffc7cadac7d6">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="eca3a0a8b3afa3a1bca0a9b8a5a3a2b3b8b5bca9d1ac">[email&#160;protected]</a>@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#170329 2:18:10 server id 1 end_log_pos 120 CRC32 0x40f62523 Start: binlog v 4, server v 5.6.35-log created 170329 2:18:10 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
BINLOG '
4qjaWA8BAAAAdAAAAHgAAAABAAQANS42LjM1LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADiqNpYEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAASMl
9kA=
'/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="6e2d21233e222b3a272120313a373e2b532e21222a">[email&#160;protected]</a>_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
</code></pre>
<p>现在在数据库中执行下面的操作:</p>
<pre><code>use test;
create table student(studentid int not null primary key,name varchar(30) not null,gender enum('female','mail'));
alter table student change gender gender enum('female','male');
insert into student values(1,'malongshuai','male'),(2,'gaoxiaofang','female');
</code></pre>
<p>再查看二进制日志信息。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f98b96968db9818c9c8190">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b2fdfef6edf1fdffe2fef7e6fbfdfcede6ebe2f78ff2">[email&#160;protected]</a>@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#170329 2:18:10 server id 1 end_log_pos 120 CRC32 0x40f62523 Start: binlog v 4, server v 5.6.35-log created 170329 2:18:10 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
BINLOG '
4qjaWA8BAAAAdAAAAHgAAAABAAQANS42LjM1LWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAADiqNpYEzgNAAgAEgAEBAQEEgAAXAAEGggAAAAICAgCAAAACgoKGRkAASMl
9kA=
'/*!*/;
# at 120
#170329 5:20:00 server id 1 end_log_pos 305 CRC32 0xbac43912 Query thread_id=1 exec_time=0 error_code=0
use `test`/*!*/;
SET TIMESTAMP=1490736000/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create table student(studentid int not null primary key,name varchar(30) not null,gender enum('female','mail'))
/*!*/;
# at 305
#170329 5:21:21 server id 1 end_log_pos 441 CRC32 0xde67f702 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1490736081/*!*/;
alter table student change gender gender enum('female','male')
/*!*/;
# at 441
#170329 5:21:33 server id 1 end_log_pos 520 CRC32 0x05a9c5a1 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1490736093/*!*/;
BEGIN
/*!*/;
# at 520
#170329 5:21:33 server id 1 end_log_pos 671 CRC32 0xad9e7dc8 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1490736093/*!*/;
insert into student values(1,'malongshuai','male'),(2,'gaoxiaofang','female')
/*!*/;
# at 671
#170329 5:21:33 server id 1 end_log_pos 702 CRC32 0xb69b0f7d Xid = 32
COMMIT/*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="14575b59445851405d5b5a4b404d445129545b5850">[email&#160;protected]</a>_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
</code></pre>
<p>将上述信息整理为下图其中timestamp记录的是从1970-01-01到现在的总秒数时间戳可以使用 date -d '@1490736093' 转换。</p>
<p><img src="assets/733013-20180507085958196.png" alt="img" /></p>
<ul>
<li>位置0-120记录的是二进制日志的一些固定信息。</li>
<li>位置120-305记录的是use和create table语句语句的记录时间为5:20:00。但注意这里的use不是执行的use语句而是MySQL发现要操作的数据库为test而自动进行的操作并记录下来。人为的use语句是不会记录的。</li>
<li>位置305-441记录的是alter table语句语句的记录时间为5:20:21。</li>
<li>位置441-702记录的是insert操作因为该操作是DML语句因此记录了事务的开始BEGIN和提交COMMIT。
<ul>
<li>begin的起止位置为441-520</li>
<li>insert into语句的起止位置为520-671记录的时间和自动开启事务的begin时间是一样的</li>
<li>commit的起止位置为671-702。</li>
</ul>
</li>
</ul>
<p>使用-r命令将日志文件导入到指定文件中使用重定向也可以实现同样的结果。并使用-s查看简化的日志文件。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a9dbc6c6dde9d1dcccd1c0">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001 -r /tmp/binlog.000001
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fb8994948fbb838e9e8392">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001 -s&gt;/tmp/binlog.sample
</code></pre>
<p>比较这两个文件,看看简化的日志文件简化了哪些东西。</p>
<p><img src="assets/733013-20180507090446176-118990478.png" alt="img" /></p>
<p>从上图中可以看出,使用-s后少了基于行的日志信息也少了记录的位置和时间信息。</p>
<p>使用-o可以忽略前N个条目例如上面的操作涉及了6个操作。忽略掉前3个后的日志显示如下可以看到直接从位置441开始显示了。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="71031e1e05310904140918">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001 -o 3
...前面固定部分省略...
'/*!*/;
# at 441
#170329 5:21:33 server id 1 end_log_pos 520 CRC32 0x05a9c5a1 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1490736093/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 520
#170329 5:21:33 server id 1 end_log_pos 671 CRC32 0xad9e7dc8 Query thread_id=1 exec_time=0 error_code=0
use `test`/*!*/;
SET TIMESTAMP=1490736093/*!*/;
insert into student values(1,'malongshuai','male'),(2,'gaoxiaofang','female')
/*!*/;
# at 671
#170329 5:21:33 server id 1 end_log_pos 702 CRC32 0xb69b0f7d Xid = 32
COMMIT/*!*/;
DELIMITER ;
...后面固定部分省略...
</code></pre>
<p>使用-d可以只显示指定数据库相关的操作。例如先切换到其他数据库进行一番操作然后再使用-d查看日志。</p>
<pre><code>mysql&gt; use mysql;
mysql&gt; create table mytest(id int);
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="cebca1a1ba8eb6bbabb6a7">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001 -d mysql
...前固定部分省略...'/*!*/;
# at 120
# at 305
# at 441
#170329 5:21:33 server id 1 end_log_pos 520 CRC32 0x05a9c5a1 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1490736093/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 520
# at 671
#170329 5:21:33 server id 1 end_log_pos 702 CRC32 0xb69b0f7d Xid = 32
COMMIT/*!*/;
# at 702
#170329 6:27:12 server id 1 end_log_pos 805 CRC32 0x491529ff Query thread_id=1 exec_time=0 error_code=0
use `mysql`/*!*/;
SET TIMESTAMP=1490740032/*!*/;
create table mytest(id int)
/*!*/;
DELIMITER ;
...后面固定部分省略...
</code></pre>
<p>可以看到除了指定的mysql数据库的信息输出了还非常简化的输出了其他数据库的信息。</p>
<p>mysqlbinlog最有用的两个选项就是指定时间和位置来输出日志。</p>
<p>指定时间时,将输出指定时间范围内的日志。指定的时间可以不和日志中记录的日志相同。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fb8994948fbb838e9e8392">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001 --start-datetime='2017-03-28 00:00:01' --stop-datetime='2017-03-29 05:21:23'
...前面固定部分省略...
'/*!*/;
# at 120
#170329 5:20:00 server id 1 end_log_pos 305 CRC32 0xbac43912 Query thread_id=1 exec_time=0 error_code=0
use `test`/*!*/;
SET TIMESTAMP=1490736000/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
create table student(studentid int not null primary key,name varchar(30) not null,gender enum('female','mail'))
/*!*/;
# at 305
#170329 5:21:21 server id 1 end_log_pos 441 CRC32 0xde67f702 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1490736081/*!*/;
alter table student change gender gender enum('female','male')
/*!*/;
DELIMITER ;
...后面固定部分省略...
</code></pre>
<p>同理指定位置也一样但是指定位置时有个要求是如果指定起始位置则必须指定日志文件中明确的起始位置。例如日志文件中有位置120、305、441可以指定起始和结束位置为120、500但是不可以指定起止位置为150、500因为日志文件中不存在150这个位置。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5c2e3333281c2429392435">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001 --start-position=150 --stop-position=441
...前面固定部分省略...
'/*!*/;
ERROR: Error in Log_event::read_log_event(): 'read error', data_len: 4202496, event_type: 0
...后面固定部分省略...
[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="94e6fbfbe0d4ece1f1ecfd">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000001 --start-position=305 --stop-position=500
...前面固定部分省略...
'/*!*/;
# at 305
#170329 5:21:21 server id 1 end_log_pos 441 CRC32 0xde67f702 Query thread_id=1 exec_time=0 error_code=0
use `test`/*!*/;
SET TIMESTAMP=1490736081/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
alter table student change gender gender enum('female','male')
/*!*/;
# at 441
#170329 5:21:33 server id 1 end_log_pos 520 CRC32 0x05a9c5a1 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1490736093/*!*/;
BEGIN
/*!*/;
DELIMITER ;
...后面固定部分省略...
</code></pre>
<h3>5.2.2 show binary logs</h3>
<p>该语句用于查看当前使用了哪些二进制日志文件。</p>
<p>可以通过查看二进制的index文件来查看当前正在使用哪些二进制日志。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aad8c5c5deead2dfcfd2c3">[email&#160;protected]</a> data]# cat mysql-bin.index
./mysql-bin.000003
./mysql-bin.000004
./mysql-bin.000005
./mysql-bin.000006
</code></pre>
<p>也可以在mysql环境中使用 show {binary | master} logs 来查看。binary和master是同义词。</p>
<pre><code>mysql&gt; show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000003 | 167 |
| mysql-bin.000004 | 785 |
| mysql-bin.000005 | 1153 |
| mysql-bin.000006 | 602 |
+------------------+-----------
</code></pre>
<h3>5.2.3 show binlog events</h3>
<p><strong>该语句用于查看日志中进行了哪些操作。</strong></p>
<pre><code>mysql&gt; show binlog events in 'mysql-bin.000005';
</code></pre>
<p><img src="assets/733013-20180507091129596-1182363918.png" alt="img" /></p>
<p>可以指定起始位置。同样,起始位置必须指定正确,不能指定不存在的位置。</p>
<pre><code>mysql&gt; show binlog events in 'mysql-bin.000005' from 961;
+------------------+------+------------+-----------+-------------+--------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+------+------------+-----------+-------------+--------------------------------+
| mysql-bin.000005 | 961 | Table_map | 1 | 1019 | table_id: 98 (test.student) |
| mysql-bin.000005 | 1019 | Write_rows | 1 | 1075 | table_id: 98 flags: STMT_END_F |
| mysql-bin.000005 | 1075 | Xid | 1 | 1106 | COMMIT /* xid=129 */ |
| mysql-bin.000005 | 1106 | Rotate | 1 | 1153 | mysql-bin.000006;pos=4 |
+------------------+------+------------+-----------+-------------+--------------------------------+
</code></pre>
<h3>5.2.4 show master status</h3>
<p>该语句用于显示主服务器中的二进制日志信息。如果是主从结构,它只会显示主从结构中主服务器的二进制日志信息。</p>
<pre><code>mysql&gt; show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000006 | 602 | | | |
+------------------+----------+--------------+------------------+-------------------+
</code></pre>
<p>可以查看到当前正在使用的日志及下一事件记录的开始位置,还能查看到哪些数据库需要记录二进制日志,哪些数据库不记录二进制日志。</p>
<h2>5.3 删除二进制日志</h2>
<p>删除二进制日志有几种方法。不管哪种方法都会将删除后的信息同步到二进制index文件中。</p>
<p><strong>1.reset master<strong><strong>将会删除所有日志并让日志文件重新从000001</strong></strong>开始。</strong></p>
<pre><code>mysql&gt; reset master;
</code></pre>
<p><strong>2.PURGE { BINARY | MASTER } LOGS { TO 'log_name' | BEFORE datetime_expr }</strong></p>
<p>purge master logs to &quot;binlog_name.00000X&quot; 将会清空00000X之前的所有日志文件。例如删除000006之前的日志文件。</p>
<pre><code>mysql&gt; purge master logs to &quot;mysql-bin.000006&quot;;
mysql&gt; purge binary logs to &quot;mysql-bin.000006&quot;;
</code></pre>
<p>master和binary是同义词</p>
<p>purge master logs before 'yyyy-mm-dd hh:mi:ss' 将会删除指定日期之前的所有日志。但是若指定的时间处在正在使用中的日志文件中将无法进行purge。</p>
<pre><code>mysql&gt; purge master logs before '2017-03-29 07:36:40';
mysql&gt; show warnings;
+---------+------+---------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------------------+
| Warning | 1868 | file ./mysql-bin.000003 was not purged because it is the active log file. |
+---------+------+---------------------------------------------------------------------------+
</code></pre>
<p><strong>3.<strong><strong>使用--expire_logs_days=N</strong></strong>选项指定过了多少天日志自动过期清空。</strong></p>
<h2>5.4 二进制日志的记录格式</h2>
<p>在MySQL 5.1之前MySQL只有一种基于语句statement形式的日志记录格式。即将所有的相关操作记录为SQL语句形式。但是这样的记录方式对某些特殊信息无法同步记录例如uuidnow()等这样动态变化的值。</p>
<p>从MySQL 5.1开始MySQL支持statement、row、mixed三种形式的记录方式。row形式是基于行来记录也就是将相关行的每一列的值都在日志中保存下来这样的结果会导致日志文件变得非常大但是保证了动态值的确定性。还有一种mixed形式表示如何记录日志由MySQL自己来决定。</p>
<p>日志的记录格式由变量 binlog_format 来指定。其值有row,statement,mixed。innodb引擎的创始人之一在博客上推荐使用row格式。</p>
<p>下面将记录格式改为row。</p>
<pre><code>mysql&gt; alter table student add birthday datetime default now();
mysql&gt; flush logs;
mysql&gt; set binlog_format='row';
mysql&gt; insert into student values(7,'xiaowoniu','female',now());
</code></pre>
<p>查看产生的日志。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3f4d50504b7f474a5a4756">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000005
...前面固定部分省略...
'/*!*/;
# at 120
#170329 8:06:24 server id 1 end_log_pos 200 CRC32 0x0ac02649 Query thread_id=1 exec_time=0 error_code=0
SET TIMESTAMP=1490745984/*!*/;
SET @@session.pseudo_thread_id=1/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1075838976/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
SET @@session.time_zone='SYSTEM'/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
BEGIN
/*!*/;
# at 200
#170329 8:06:24 server id 1 end_log_pos 258 CRC32 0xb8cdfd09 Table_map: `test`.`student` mapped to number 94
# at 258
#170329 8:06:24 server id 1 end_log_pos 314 CRC32 0x8ce6f72c Write_rows: table id 94 flags: STMT_END_F
BINLOG '
gPraWBMBAAAAOgAAAAIBAAAAAF4AAAAAAAEABHRlc3QAB3N0dWRlbnQABAMP/hIFHgD3AQAMCf3N
uA==
gPraWB4BAAAAOAAAADoBAAAAAF4AAAAAAAEAAgAE//AHAAAACXhpYW93b25pdQGZnDqBmCz35ow=
'/*!*/;
# at 314
#170329 8:06:24 server id 1 end_log_pos 345 CRC32 0x7a48c057 Xid = 114
COMMIT/*!*/;
DELIMITER ;
...后面固定部分省略...
</code></pre>
<p>发现是一堆看不懂的东西,使用-vv可将这些显示出来。可以看出结果中记录的非常详细这也是为什么基于row记录日志会导致日志文件极速变大。</p>
<pre><code>[<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c6b4a9a9b286beb3a3beaf">[email&#160;protected]</a> data]# mysqlbinlog mysql-bin.000005 -vv
...前面省略...
BINLOG '
gPraWBMBAAAAOgAAAAIBAAAAAF4AAAAAAAEABHRlc3QAB3N0dWRlbnQABAMP/hIFHgD3AQAMCf3N
uA==
gPraWB4BAAAAOAAAADoBAAAAAF4AAAAAAAEAAgAE//AHAAAACXhpYW93b25pdQGZnDqBmCz35ow=
'/*!*/;
### INSERT INTO `test`.`student`
### SET
### @1=7 /* INT meta=0 nullable=0 is_null=0 */
### @2='xiaowoniu' /* VARSTRING(30) meta=30 nullable=0 is_null=0 */
### @3=1 /* ENUM(1 byte) meta=63233 nullable=1 is_null=0 */
### @4='2017-03-29 08:06:24' /* DATETIME(0) meta=0 nullable=1 is_null=0 */
# at 314
...后面省略...
</code></pre>
<p>还有一种mixed模式。这种模式下默认会采用statement的方式记录只有以下几种情况会采用row的形式来记录日志。
1.表的存储引擎为NDB这时对表的DML操作都会以row的格式记录。
2.使用了uuid()、user()、current_user()、found_rows()、row_count()等不确定函数。但测试发现对now()函数仍会以statement格式记录而sysdate()函数会以row格式记录。
3.使用了insert delay语句。
4.使用了临时表。</p>
<h2>5.5 二进制日志相关的变量</h2>
<p>注意在配置binlog相关变量的时候相关变量名总是搞混因为有的是binlog有的是log_bin当他们分开的时候log在前当它们一起的时候bin在前。在配置文件中也同样如此。</p>
<ul>
<li>log_bin = {on | off | base_name} #指定是否启用记录二进制日志或者指定一个日志路径(路径不能加.否则.后的被忽略)</li>
<li>sql_log_bin ={ on | off } #指定是否启用记录二进制日志只有在log_bin开启的时候才有效</li>
<li>expire_logs_days = #指定自动删除二进制日志的时间,即日志过期时间</li>
<li>binlog_do_db = #明确指定要记录日志的数据库</li>
<li>binlog_ignore_db = #指定不记录二进制日志的数据库</li>
<li>log_bin_index = #指定mysql-bin.index文件的路径</li>
<li>binlog_format = { mixed | row | statement } #指定二进制日志基于什么模式记录</li>
<li>binlog_rows_query_log_events = { 1|0 } # MySQL5.6.2添加了该变量当binlog format为row时默认不会记录row对应的SQL语句设置为1或其他true布尔值时会记录但需要使用mysqlbinlog -v查看这些语句是被注释的恢复时不会被执行。</li>
<li>max_binlog_size = #指定二进制日志文件最大值,超出指定值将自动滚动。但由于事务不会跨文件,所以并不一定总是精确。</li>
<li>binlog_cache_size = 32768 #<strong>基于事务类型的日志会先记录在缓冲区</strong>,当达到该缓冲大小时这些日志会写入磁盘</li>
<li>max_binlog_cache_size = #指定二进制日志缓存最大大小硬限制。默认4G够大了建议不要改</li>
<li>binlog_cache_use使用缓存写二进制日志的次数(这是一个实时变化的统计值)</li>
<li>binlog_cache_disk_use:使用临时文件写二进制日志的次数当日志超过了binlog_cache_size的时候会使用临时文件写日志如果该变量值不为0则考虑增大binlog_cache_size的值</li>
<li>binlog_stmt_cache_size = 32768 #一般等同于且决定binlog_cache_size大小所以修改缓存大小时只需修改这个而不用修改binlog_cache_size</li>
<li>binlog_stmt_cache_use使用缓存写二进制日志的次数</li>
<li>binlog_stmt_cache_disk_use: 使用临时文件写二进制日志的次数当日志超过了binlog_cache_size的时候会使用临时文件写日志如果该变量值不为0则考虑增大binlog_cache_size的值</li>
<li>sync_binlog = { 0 | n } #这个参数直接影响mysql的性能和完整性
<ul>
<li>sync_binlog=0:不同步日志何时刷到磁盘由FileSystem决定这个性能最好。</li>
<li>sync_binlog=n:每写n次事务(注意对于非事务表来说是n次事件对于事务表来说是n次事务而一个事务里可能包含多个二进制事件)MySQL将执行一次磁盘同步指令fdatasync()将缓存日志刷新到磁盘日志文件中。Mysql中默认的设置是sync_binlog=0即不同步这时性能最好但风险最大。一旦系统奔溃缓存中的日志都会丢失。</li>
</ul>
</li>
</ul>
<p><strong>在innodb的主从复制结构中如果启用了二进制日志(几乎都会启用)要保证事务的一致性和持久性的时候必须将sync_binlog的值设置为1因为每次事务提交都会写入二进制日志设置为1就保证了每次事务提交时二进制日志都会写入到磁盘中从而立即被从服务器复制过去。</strong></p>
<h2>5.6 二进制日志定点还原数据库</h2>
<p>只需指定二进制日志的起始位置可指定终止位置并将其保存到sql文件中由mysql命令来载入恢复即可。当然直接通过管道送给mysql命令也可。</p>
<p>至于是基于位置来恢复还是基于时间点来恢复,这两种行为都可以。选择时间点来恢复比较直观些,并且跨日志文件恢复时更方便。</p>
<pre><code>mysqlbinlog --stop-datetime=&quot;2014-7-2 15:27:48&quot; /tmp/mysql-bin.000008 | mysql -u user -p password
</code></pre>
<p>恢复多个二进制日志文件时:</p>
<pre><code>mysqlbinlog mysql-bin.[*] | mysql -uroot -p password
</code></pre>
<p>或者将它们导入到一个文件中后恢复。</p>
<pre><code>mysqlbinlog mysql-bin.000001 &gt; /tmp/a.sql
mysqlbinlog mysql-bin.000002 &gt;&gt;/tmp/a.sql
mysql -u root -p password -e &quot;source /tmp/a.sql&quot;
</code></pre>
</div>
</div>
<div>
<div style="float: left">
<a href="/文章/MySQL 故障诊断:教你快速定位加锁的 SQL.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/文章/MySQL 的半同步是什么?.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70998001f9be8b66","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>