<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title>Abul成长之路</title>
        <link>http://www.tusundong.top</link>
        <description>Abul的个人博客</description>
        <atom:link href="http://www.tusundong.top/rss.html" rel="self" />
        <language>zh-cn</language>
        <lastBuildDate>Thu, 23 Apr 2026 12:25:14 GMT</lastBuildDate>
        <item>
            <title>神奇的MDL</title>
            <link>http://www.tusundong.top/post/shen-qi-de-MDL.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-114">问题复现</a></li>
</ul>
</div><p>早上RD突然发消息说，有个DDL<code>alter table xx modify column col varchar(10)</code>无法执行。<br>一开始以为是个简单的长事务没有关闭，对表xx加了S锁。熟练的查询<code>select * from information_schema.innodb_trx;</code>竟然没有数据！再查一下processlist，alter table xx的进程真的是出于Waiting for table metadata lock。此时判断可能真没长事务，但有高频查询SQL ，导致DDL无法获取到X锁。看了下监控指标，查询QPS竟然也不高...此时跟RD反馈，让他把本地的SQL查询工具关了。alter执行成功！反馈说有开了另外一个窗口进行事务insert，但执行报错。  </p>
<h3><a id="toc-114" class="anchor" href="#toc-114"></a>问题复现</h3>
<pre><code class="hljs lang-sql">会话一：
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> tmp(id <span class="hljs-type">int</span>,val <span class="hljs-type">varchar</span>(<span class="hljs-number">5</span>));
<span class="hljs-keyword">begin</span>;
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> tmp <span class="hljs-keyword">values</span>(<span class="hljs-number">1</span>,<span class="hljs-string">&#x27;aaaaaa&#x27;</span>);  <span class="hljs-comment">/*执行报错，事务没关闭*/</span>

会话二：
<span class="hljs-keyword">alter</span> <span class="hljs-keyword">table</span> tmp modify <span class="hljs-keyword">column</span> val <span class="hljs-type">varchar</span>(<span class="hljs-number">10</span>); <span class="hljs-comment">/*MDL锁等待*/</span>

会话三：
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> information_schema.innodb_trx; <span class="hljs-comment">/*查无会话一对应的长事务*/</span>
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> performance_schema.metadata_locks;
</code></pre>
<p>疑问：</p>
<ol>
<li>会话三为何查无会话一的长事务，因为innodb_trx仅记录已成功开始执行的活跃事务，会话一开始就执行失败。</li>
<li>如何定位到是会话一导致的？（开启PS，select * from performance_schema.metadata_locks）</li>
</ol>

            ]]></description>
            <pubDate>Tue, 30 Sep 2025 03:29:22 GMT</pubDate>
            <guid>http://www.tusundong.top/post/shen-qi-de-MDL.html</guid>
        </item>
        <item>
            <title>grafana sqlite3转mysql</title>
            <link>http://www.tusundong.top/post/grafana sqlite3-zhuan-mysql.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-8e1">背景</a></li>
<li><a href="#toc-4b8">解决</a><ul>
<li><a href="#toc-216">迁移过程的参考步骤​</a></li>
</ul>
</li>
</ul>
</div><blockquote>
<p>引用自<a href="https://blog.yousri.org/posts/change-grafana-db-to-mysql.html">迁移Grafana 默认的 SQLite DB 数据改为使用 MySQL 方式</a></p>
</blockquote>
<h3><a id="toc-8e1" class="anchor" href="#toc-8e1"></a>背景</h3>
<p>grafana默认使用sqlite3存储数据，数据量上升需调整为MySQL，涉及将SQLite数据转MySQL。
一开始搜索文档为sqlite to mysql，各种折腾，比较有参考意义的，如：<a href="https://study-database.readthedocs.io/zh/latest/%E6%95%B0%E6%8D%AE%E5%BA%9304sqlite%E8%BD%ACmysql.html#sqlitesql">https://study-database.readthedocs.io/zh/latest/%E6%95%B0%E6%8D%AE%E5%BA%9304sqlite%E8%BD%ACmysql.html#sqlitesql</a> ，总结了各种方案，遇到的坑，虽然最后也没采用。如果直接转换，涉及字段类型text可能需转换成varchar，或者text，因此表结构最好直接通过grafana来生成。</p>
<h3><a id="toc-4b8" class="anchor" href="#toc-4b8"></a>解决</h3>
<h4><a id="toc-216" class="anchor" href="#toc-216"></a>迁移过程的参考步骤​</h4>
<ul>
<li>首先需要暂停 Grafana 服务，导出默认的 SQLite 数据库文件，如 grafana.db ；</li>
<li>可借助 Grafana 官方提供的工具 database-migrator 将数据库导出转化为支持 MySQL 协议的 SQL 文件；</li>
<li>修改 Grafana 配置文件 grafana.ini 数据库相关配置参数 -e &quot;GF_DATABASE_URL=mysql://$db_username:$db_passwd@$db_host:$db_port/$db_name&quot; 使用 MySQL 数据库；</li>
<li>重新启动 Grafana 让其在 MySQL 中设置数据库和表结构，初始化完再先关停下 Grafana ；</li>
<li>导入前面使用工具从 SQLLite 原生默认数据库中导出的 sql 数据到 MySQL 对应的 DB 中；</li>
<li>重新开启 Grafana 按理即可；</li>
</ul>
<p>附：</p>
<ol>
<li>grafana官方文档：<a href="https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/">https://grafana.com/docs/grafana/latest/setup-grafana/installation/docker/</a></li>
<li>database-migrator：<a href="https://github.com/grafana/database-migrator">https://github.com/grafana/database-migrator</a></li>
</ol>

            ]]></description>
            <pubDate>Tue, 11 Mar 2025 07:06:46 GMT</pubDate>
            <guid>http://www.tusundong.top/post/grafana sqlite3-zhuan-mysql.html</guid>
        </item>
        <item>
            <title>MySQL8异常中断Forcing close of thread 24 user: xxx</title>
            <link>http://www.tusundong.top/post/MySQL8-yi-chang-zhong-duan-Forcing close of thread 24 user: xxx.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-6ba">ubuntu自动升级一些事</a></li>
</ul>
</div><ol>
<li>环境：ubuntu22.04 mysql8.0.39</li>
<li>问题：mysql服务突然停止shutdown，查看mysql异常日志如下：</li>
</ol>
<pre><code class="hljs lang-crmsh">Received SHUTDOWN from <span class="hljs-keyword">user</span> <span class="hljs-title">&lt;via</span> <span class="hljs-keyword">user</span> <span class="hljs-title">signal</span>&gt;. Shutting down mysqld (<span class="hljs-keyword">Version</span>: <span class="hljs-number">8.0</span>.<span class="hljs-number">39</span>-<span class="hljs-number">0</span>ubuntu0.<span class="hljs-number">22.04</span>.<span class="hljs-number">1</span>).
/usr/sbin/mysqld: Forcing close of thread <span class="hljs-number">24</span>  user: &#x27;zabbix&#x27;.
/usr/sbin/mysqld: Shutdown complete (mysqld <span class="hljs-number">8.0</span>.<span class="hljs-number">39</span>-<span class="hljs-number">0</span>ubuntu0.<span class="hljs-number">22.04</span>.<span class="hljs-number">1</span>)  (Ubuntu).
</code></pre>
<ol start="3">
<li>排查：</li>
</ol>
<ul>
<li>查资料，有的说是DNS反向解析导致mysql异常停止，要开启skip-name-resolve，查my.cnf已开启。</li>
<li>查看/var/log/syslog和journalctl -xe<br>  发现每次mysql停止前都会出现启动<strong>apt-daily-upgrade.service</strong>，而该服务是每天定时更新服务upgrade and clean activities，再查/var/log/apt/term.log也看到了确实是更新的时候触发mysql shutdown，也有出现mysql被直接升级到最新</li>
</ul>
<ol start="4">
<li>解决：<br>  卸载mysql服务（当时dpkg安装），重新安装；或者停止apt-daily-upgrade</li>
</ol>
<h3><a id="toc-6ba" class="anchor" href="#toc-6ba"></a>ubuntu自动升级一些事</h3>
<ol>
<li>触发服务apt-daily和apt-daily-upgrade<br>systemctl status apt-daily-upgrade查看，都是调用同一个脚本/usr/lib/apt/apt.systemd.daily</li>
<li>何为apt-daily-upgrade<br>顾名思义就是自动升级。<br>  是否开启自动升级、自动升级规则，查看目录/etc/apt/apt.conf.d/<br>  重点关注50unattended-upgrades（无人值守自动升级），默认都是开启，每日6点多默默后台升级</li>
<li>查看日志<br>已自动升级日志：/var/log/apt/history.log<br>升级日志明细（含kill）：/var/log/apt/term.log</li>
<li>自动升级规则<br>/etc/apt/apt.conf.d/50unattended-upgrades</li>
</ol>
<pre><code class="hljs lang-nsis"> Unattended-<span class="hljs-class">Upgrade::Allowed</span>-Origins {
      <span class="hljs-string">&quot;<span class="hljs-variable">${distro_id}</span>:<span class="hljs-variable">${distro_codename}</span>&quot;</span><span class="hljs-comment">;</span>
      <span class="hljs-string">&quot;<span class="hljs-variable">${distro_id}</span>:<span class="hljs-variable">${distro_codename}</span>-security&quot;</span><span class="hljs-comment">;</span>
      <span class="hljs-string">&quot;<span class="hljs-variable">${distro_id}</span>ESMApps:<span class="hljs-variable">${distro_codename}</span>-apps-security&quot;</span><span class="hljs-comment">;</span>
      <span class="hljs-string">&quot;<span class="hljs-variable">${distro_id}</span>ESM:<span class="hljs-variable">${distro_codename}</span>-infra-security&quot;</span><span class="hljs-comment">;</span>
 }<span class="hljs-comment">;</span>
</code></pre>
<p>  ${distro_id}代表发行版的ID（如Ubuntu）；<br>  ${distro_codename}代表发行版的代号（如jammy，对应于Ubuntu 22.04）</p>
<pre><code class="hljs lang-pgsql">例如：`apt <span class="hljs-keyword">search</span> mysql-<span class="hljs-keyword">server</span>` （如下版本就支持自动升级）  
mysql-<span class="hljs-keyword">server</span><span class="hljs-number">-8.0</span>/jammy-updates,jammy-<span class="hljs-keyword">security</span> <span class="hljs-number">8.0</span><span class="hljs-number">.37</span><span class="hljs-number">-0</span>ubuntu0<span class="hljs-number">.22</span><span class="hljs-number">.04</span><span class="hljs-number">.3</span> amd64
</code></pre>
<ol start="5">
<li>已安装包查看是否会被自动升级<br><code>apt policy mysql-server</code></li>
</ol>
<pre><code class="hljs lang-apache"><span class="hljs-attribute">mysql</span>-server:
  <span class="hljs-attribute">Installed</span>: (none)						(已安装版本)
  <span class="hljs-attribute">Candidate</span>: <span class="hljs-number">8</span>.<span class="hljs-number">0</span>.<span class="hljs-number">37</span>-<span class="hljs-number">0</span>ubuntu<span class="hljs-number">0.22.04.3</span>	(候选版本)
  <span class="hljs-attribute">Version</span> table:						(版本表)
     <span class="hljs-attribute">8</span>.<span class="hljs-number">0</span>.<span class="hljs-number">37</span>-<span class="hljs-number">0</span>ubuntu<span class="hljs-number">0.22.04.3</span> <span class="hljs-number">500</span>
        <span class="hljs-attribute">500</span> http://cn.archive.ubuntu.com/ubuntu jammy-updates/main amd<span class="hljs-number">64</span> Packages
        <span class="hljs-attribute">500</span> http://cn.archive.ubuntu.com/ubuntu jammy-security/main amd<span class="hljs-number">64</span> Packages
     <span class="hljs-attribute">8</span>.<span class="hljs-number">0</span>.<span class="hljs-number">28</span>-<span class="hljs-number">0</span>ubuntu<span class="hljs-number">4</span> <span class="hljs-number">500</span>
        <span class="hljs-attribute">500</span> http://cn.archive.ubuntu.com/ubuntu jammy/main amd<span class="hljs-number">64</span> Packages
</code></pre>
<ol start="6">
<li>经验<br>因此，如果使用apt安装来自ubuntu官方源的包，可能会被静默升级，导致服务不可用。</li>
</ol>

            ]]></description>
            <pubDate>Sat, 10 Aug 2024 06:28:27 GMT</pubDate>
            <guid>http://www.tusundong.top/post/MySQL8-yi-chang-zhong-duan-Forcing close of thread 24 user: xxx.html</guid>
        </item>
        <item>
            <title>零宽字符导致MySQL表神奇消失</title>
            <link>http://www.tusundong.top/post/ling-kuan-zi-fu-dao-zhi-MySQL-biao-shen-qi-xiao-shi.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-90c">复现</a></li>
<li><a href="#toc-21d">思考</a></li>
</ul>
</div><p>很久没写文章了，今天看了篇文章《<a href="https://opensource.actionsky.com/%e6%8a%80%e6%9c%af%e5%88%86%e4%ba%ab-mysql-%e5%88%9b%e5%bb%ba%e8%a1%a8%e5%90%8e%e7%a5%9e%e7%a7%98%e6%b6%88%e5%a4%b1%ef%bc%9f%e6%8f%ad%e7%a7%98%e9%9b%b6%e5%ae%bd%e5%ad%97%e7%ac%a6%e9%99%b7%e9%98%b1/">MySQL 创建表后神秘消失？揭秘零宽字符陷阱</a>》，一开始也是被标题吸引进去。  </p>
<h3><a id="toc-90c" class="anchor" href="#toc-90c"></a>复现</h3>
<pre><code class="hljs lang-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `lang​` (
  `id` <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;主键自增&#x27;</span>,
  `create_time` datetime <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;创建时间&#x27;</span>,
  <span class="hljs-keyword">PRIMARY</span> KEY (`id`)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8;

# <span class="hljs-keyword">show</span> tables;可看到表lang，但直接<span class="hljs-keyword">select</span>查不到
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> lang;
ERROR <span class="hljs-number">1146</span> (<span class="hljs-number">42</span>S02): <span class="hljs-keyword">Table</span> <span class="hljs-string">&#x27;test.lang&#x27;</span> doesn<span class="hljs-string">&#x27;t exist
</span></code></pre>
<p>原因为lang后面含有零宽字符
<img src="https://www.tusundong.top/static/upload/20240430/upload_b4bf15f4a4c4b2c1a66abe739c6cfd76.png" alt="image.png"></p>
<h3><a id="toc-21d" class="anchor" href="#toc-21d"></a>思考</h3>
<ol>
<li>原文中已经说了如何解决，例如复制到编辑器中可能会提示异常符号、show tables查看的时候边框线 “|” 与其他行是不对齐的。  </li>
<li>而我的排查方式不一样，第一直觉就是觉得里面含有特殊字符，直接查hex字符。</li>
</ol>
<pre><code class="hljs lang-sql">abul test<span class="hljs-operator">&gt;</span><span class="hljs-keyword">select</span> hex(table_name),hex(<span class="hljs-string">&#x27;lang&#x27;</span>) <span class="hljs-keyword">from</span> information_schema.tables <span class="hljs-keyword">where</span> table_schema<span class="hljs-operator">=</span><span class="hljs-string">&#x27;test&#x27;</span> <span class="hljs-keyword">and</span> table_namelike <span class="hljs-string">&#x27;lang%&#x27;</span>;
<span class="hljs-operator">+</span><span class="hljs-comment">-----------------+-------------+</span>
<span class="hljs-operator">|</span> hex(table_name) <span class="hljs-operator">|</span> hex(<span class="hljs-string">&#x27;lang&#x27;</span>) <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-comment">-----------------+-------------+</span>
<span class="hljs-operator">|</span> <span class="hljs-number">6</span>C616E67E2808B  <span class="hljs-operator">|</span> <span class="hljs-number">6</span>C616E67    <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-comment">-----------------+-------------+</span>
<span class="hljs-number">1</span> <span class="hljs-type">row</span> <span class="hljs-keyword">in</span> <span class="hljs-keyword">set</span> (<span class="hljs-number">0.00</span> sec)
</code></pre>
<ol start="3">
<li>另外，如何避免？上线SQL正常会经过goInception审核，那如何避免RD提交类似特殊字符。可能得正则查找。</li>
</ol>
<pre><code class="hljs lang-undefined">get_first_zero_width_char_pos(sql:str) -&gt; int:
    &quot;&quot;&quot;
    查找第一个零宽字符的位置，无零宽字符返回-1
    &quot;&quot;&quot;
    zwc = re.search(r&#x27;[\u200B-\u200D\u2060\uFEFF]&#x27;, sql)
    return zwc.start() if zwc else -1
</code></pre>
<ol start="4">
<li>零宽字符大多数情况不可见，那会用在什么地方？某些社交平台，敏感词汇会被脱敏，这样是否就可以反脱敏。</li>
</ol>

            ]]></description>
            <pubDate>Tue, 30 Apr 2024 01:36:13 GMT</pubDate>
            <guid>http://www.tusundong.top/post/ling-kuan-zi-fu-dao-zhi-MySQL-biao-shen-qi-xiao-shi.html</guid>
        </item>
        <item>
            <title>DTS同步引发的存储过程执行报错</title>
            <link>http://www.tusundong.top/post/DTS-tong-bu-yin-fa-de-cun-chu-guo-cheng-zhi-xing-bao-cuo.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-90c">复现</a></li>
<li><a href="#toc-772">排查</a><ul>
<li><a href="#toc-5e1">1. 权限</a></li>
<li><a href="#toc-393">2. 手动执行</a></li>
<li><a href="#toc-f94">3. 比对存储过程</a></li>
</ul>
</li>
<li><a href="#toc-54b">结论</a></li>
</ul>
</div><p>场景：今天OP反馈使用DTS将zabbix同步到新实例，原先旧实例执行存储过程<code>call partition_maintenance_all(&#39;zabbix&#39;)</code>成功，迁移到新实例后，执行报错，提示如下：</p>
<pre><code class="hljs lang-pgsql"><span class="hljs-keyword">ALTER</span> command denied <span class="hljs-keyword">to</span> <span class="hljs-keyword">user</span> <span class="hljs-string">&#x27;db_arch_w&#x27;</span>@<span class="hljs-string">&#x27;x.x.x.x&#x27;</span> <span class="hljs-keyword">for</span> <span class="hljs-keyword">table</span> <span class="hljs-string">&#x27;history&#x27;</span>
</code></pre>
<h3><a id="toc-90c" class="anchor" href="#toc-90c"></a>复现</h3>
<pre><code class="hljs lang-vala"><span class="hljs-meta"># 旧实例，执行成功</span>
mysql -h [旧实例地址] -u db_arch_w -p zabbix -e <span class="hljs-string">&quot;call partition_maintenance_all(&#x27;zabbix&#x27;);&quot;</span>

<span class="hljs-meta"># 新实例，执行报错，提示`ALTER command denied`</span>
mysql -h [新实例地址] -u db_arch_w -p zabbix -e <span class="hljs-string">&quot;call partition_maintenance_all(&#x27;zabbix&#x27;);&quot;</span>
</code></pre>
<h3><a id="toc-772" class="anchor" href="#toc-772"></a>排查</h3>
<h4><a id="toc-5e1" class="anchor" href="#toc-5e1"></a>1. 权限</h4>
<p>提示没权限，首先比对下新旧实例db_arch_w的权限，竟然都一样，如下，且没有zabbix库的ALTER权限！ </p>
<pre><code class="hljs lang-n1ql">show grants for &#x27;db_arch_w&#x27;@&#x27;%&#x27;;
+---------------------------------------------------------------------------------------------------------------------------------+
| Grants for db_arch_w@%                                                                                                          |
+---------------------------------------------------------------------------------------------------------------------------------+
| GRANT <span class="hljs-keyword">SELECT</span>, <span class="hljs-keyword">INSERT</span>, <span class="hljs-keyword">UPDATE</span>, <span class="hljs-keyword">DELETE</span>, <span class="hljs-keyword">CREATE</span>, REPLICATION SLAVE, REPLICATION CLIENT <span class="hljs-keyword">ON</span> *.* <span class="hljs-keyword">TO</span> <span class="hljs-symbol">`db_arch_w`</span>@<span class="hljs-symbol">`%`</span> <span class="hljs-keyword">WITH</span> <span class="hljs-keyword">GRANT</span> <span class="hljs-keyword">OPTION</span> |
| <span class="hljs-keyword">GRANT</span> SHOW_ROUTINE <span class="hljs-keyword">ON</span> *.* <span class="hljs-keyword">TO</span> <span class="hljs-symbol">`db_arch_w`</span>@<span class="hljs-symbol">`%`</span> <span class="hljs-keyword">WITH</span> <span class="hljs-keyword">GRANT</span> <span class="hljs-keyword">OPTION</span>                                                                  |
| <span class="hljs-keyword">GRANT</span> <span class="hljs-keyword">EXECUTE</span> <span class="hljs-keyword">ON</span> <span class="hljs-symbol">`zabbix`</span>.* <span class="hljs-keyword">TO</span> <span class="hljs-symbol">`db_arch_w`</span>@<span class="hljs-symbol">`%`</span>                                                                                  |
+---------------------------------------------------------------------------------------------------------------------------------+
</code></pre>
<p>确实没有<code>ALTER</code>权限，但旧实例为什么能执行？</p>
<h4><a id="toc-393" class="anchor" href="#toc-393"></a>2. 手动执行</h4>
<p>看了下报错的位置，手动执行，执行SQL如下</p>
<pre><code class="hljs lang-vala"><span class="hljs-meta"># 新实例，alter报错，提示ALTER command denied</span>
mysql -h [新实例地址] -u db_arch_w -p zabbix -e <span class="hljs-string">&quot;alter table zabbix.history add partition (partition p202403260000 values less than(1711468800))&quot;</span>

<span class="hljs-meta"># 旧实例，一样报错</span>
mysql -h [旧实例地址] -u db_arch_w -p zabbix -e <span class="hljs-string">&quot;alter table zabbix.history add partition (partition p202403260000 values less than(1711468800))&quot;</span>
</code></pre>
<p>这个时候新旧报错又是一致的，这是为什么呢？</p>
<h4><a id="toc-f94" class="anchor" href="#toc-f94"></a>3. 比对存储过程</h4>
<p>其实在第2步的时候，就可以确定是存储过程有问题。</p>
<pre><code class="hljs lang-n1ql"># 旧实例存储过程
<span class="hljs-keyword">CREATE</span> DEFINER=<span class="hljs-symbol">`admin`</span>@<span class="hljs-symbol">`%`</span> <span class="hljs-keyword">PROCEDURE</span> <span class="hljs-symbol">`partition_maintenance_all`</span>(
<span class="hljs-keyword">IN</span> <span class="hljs-symbol">`SCHEMA_NAME`</span> varchar(<span class="hljs-number">32</span>) charset utf8mb4 <span class="hljs-keyword">collate</span> utf8mb4_0900_ai_ci )
<span class="hljs-keyword">BEGIN</span>
    # xxx 具体内容，忽略
<span class="hljs-keyword">END</span>


# 新实例存储过程
<span class="hljs-keyword">CREATE</span> DEFINER=<span class="hljs-symbol">`admin`</span>@<span class="hljs-symbol">`%`</span> <span class="hljs-keyword">PROCEDURE</span> <span class="hljs-symbol">`partition_maintenance_all`</span>(
<span class="hljs-keyword">IN</span> <span class="hljs-symbol">`SCHEMA_NAME`</span> varchar(<span class="hljs-number">32</span>) charset utf8mb4 <span class="hljs-keyword">collate</span> utf8mb4_0900_ai_ci )
    SQL SECURITY INVOKER
<span class="hljs-keyword">BEGIN</span>
    # xxx 具体内容，忽略
<span class="hljs-keyword">END</span>
</code></pre>
<p>有个细微区别，新实例存储过程中含有<code>SQL SECURITY INVOKER</code>，其含义为执行权限使用<strong>调用者</strong>账号所属权限。例如我们一开始用<code>db_arch_w</code>账号连接，则使用<code>db_arch_w</code>的权限去执行，而存储过程中含有ALTER命令，db_arch_w没有权限就报错；而旧实例没有指定SQL SECURITY，则默认使用DEFINER定义者的权限，此处为admin账号权限（超管），因此执行不会报错。</p>
<blockquote>
<p>SQL SECURITY：有两个值DEFINER和INVOKER，没有指定则默认DEFINER。<br> DEFINER：使用定义者权限；INVOKER：使用调用者权限。</p>
</blockquote>
<h3><a id="toc-54b" class="anchor" href="#toc-54b"></a>结论</h3>
<p>DTS同步时，存储过程会自动添加<code>SQL SECURITY INVOKER</code>，导致调用时使用的是调用者的权限，当存储过程中含有调用者没有的权限时就会报错。因此仅需删除所有存储过程中<code>SQL SECURITY INVOKER</code>即可执行。</p>
<p>思考：为什么DTS要指定INVOKER呢？可能是考虑同步的目标实例没有定义的用户，会导致无法执行。</p>

            ]]></description>
            <pubDate>Mon, 11 Mar 2024 04:39:43 GMT</pubDate>
            <guid>http://www.tusundong.top/post/DTS-tong-bu-yin-fa-de-cun-chu-guo-cheng-zhi-xing-bao-cuo.html</guid>
        </item>
        <item>
            <title>浅谈MySQL json类型</title>
            <link>http://www.tusundong.top/post/mysql_json.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-75e">浅谈MySQL json类型</a><ul>
<li><a href="#toc-63c">一、官网说明</a></li>
<li><a href="#toc-63a">二、使用说明</a></li>
<li><a href="#toc-5d2">三、建议</a></li>
</ul>
</li>
</ul>
</div><h1><a id="toc-75e" class="anchor" href="#toc-75e"></a>浅谈MySQL json类型</h1>
<blockquote>
<p>mysql很早就已经支持原生的json数据类型（从MySQL 5.7.8起），但目前看还是有些开发同学<strong>不了解</strong>，或者<strong>不敢用</strong>json类型。下面我们一起来学习下官网mysql的json类型。
{.is-info}</p>
</blockquote>
<h2><a id="toc-63c" class="anchor" href="#toc-63c"></a>一、官网说明</h2>
<blockquote>
<p><code>As of MySQL 5.7.8, MySQL supports a native JSON data type defined by RFC 7159 that enables efficient access to data in JSON (JavaScript Object Notation) documents. The JSON data type provides these advantages over storing JSON-format strings in a string column:</code>
从MySQL5.7.8开始，mysql支持RFC 7159定义的原生JSON数据类型，能够有效访问JSON文档中的数据。相比于存储于字符串，json类型存储有以下优点：<br/>
  <code>Automatic validation of JSON documents stored in JSON columns. Invalid documents produce an error.</code>
  自动校验json文档是否正确，不合法的值将返回error。<br/>
  <code>Optimized storage format. JSON documents stored in JSON columns are converted to an internal format that permits quick read access to document elements. When the server later must read a JSON value stored in this binary format, the value need not be parsed from a text representation. The binary format is structured to enable the server to look up subobjects or nested values directly by key or array index without reading all values before or after them in the document.</code>
  优化存储格式。存储在json列中的json文档会被转换成内部格式，使得更快访问文档里面的元素。当服务器需要读取以二进制格式存储的JSON值时，不需要从文本中解析。二进制格式结构化能时服务器直接通过键值或者数组索引查找对应值，而不需要访问之前或之后的所有值。<br/>
<code>The space required to store a JSON document is roughly the same as for LONGBLOB or LONGTEXT; see Section 11.7, “Data Type Storage Requirements”, for more information. It is important to keep in mind that the size of any JSON document stored in a JSON column is limited to the value of the max_allowed_packet system variable.</code>
JSON文档占用的空间与LONGBLOB或者LONGTEXT基本等同。JSON列的大小受限于max_allowed_packet变量的值。<br/>
<code>A JSON column cannot have a non-NULL default value.</code>
JSON类型不能有非空默认值。<br/>
<code>JSON columns, like columns of other binary types, are not indexed directly; instead, you can create an index on a generated column that extracts a scalar value from the JSON column. </code>
JSON字段跟其它二进制类型一样，不能直接创建索引；但是可以通过在生成的列上创建一个索引，生成的列指向JSON里的标量值。</p>
</blockquote>
<p>参考文档：<a href="https://dev.mysql.com/doc/refman/5.7/en/json.html">https://dev.mysql.com/doc/refman/5.7/en/json.html</a></p>
<p><strong>总结：</strong></p>
<ol>
<li><p>mysql5.7.8开始支持json类型（开发、测试、生产MySQL版本5.7.18，支持√）；  </p>
</li>
<li><p>相比于使用varchar存储，json类型能自动校验json格式是否正确；</p>
</li>
<li><p>能直接访问json对象里的键值对；</p>
</li>
<li><p>占用空间大，能存储大字段
  理论能存储<code>字符数num = max_allowed_packet / 单字符大小(字母1，中文3，emoji4)</code>  </p>
</li>
<li><p>JSON类型不能有非空默认值；</p>
</li>
</ol>
<pre><code class="hljs lang-sql"><span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> t_json(
  json_wrong json <span class="hljs-keyword">not</span> <span class="hljs-keyword">null</span> <span class="hljs-keyword">default</span> <span class="hljs-string">&#x27;{}&#x27;</span>,   <span class="hljs-comment">--&gt; 这是错的，不能有非空默认值</span>
  json_right json <span class="hljs-keyword">null</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">null</span>        <span class="hljs-comment">--&gt; 这是允许的，default null</span>
)
</code></pre>
<ol start="6">
<li>json字段不能直接建索引，但可以通过创建虚拟列，指向JSON里的对应key来创建索引。</li>
</ol>
<h2><a id="toc-63a" class="anchor" href="#toc-63a"></a>二、使用说明</h2>
<pre><code class="hljs lang-sql"><span class="hljs-comment">-- 创建表</span>
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> t_json(
  id <span class="hljs-type">int</span> unsigned <span class="hljs-keyword">not</span> <span class="hljs-keyword">null</span> auto_increment,
  json_data json <span class="hljs-keyword">null</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">null</span> comment <span class="hljs-string">&#x27;json类型字段&#x27;</span>,
  <span class="hljs-keyword">primary</span> key(id)
)comment <span class="hljs-string">&#x27;创建json类型表&#x27;</span>;

<span class="hljs-comment">-- 插入数据，跟字符串一样</span>
<span class="hljs-keyword">insert</span> <span class="hljs-keyword">into</span> t_json(json_data) <span class="hljs-keyword">values</span>(<span class="hljs-string">&#x27;{&quot;id&quot;:1, &quot;name&quot;:&quot;abul&quot;}&#x27;</span>);

<span class="hljs-comment">-- 查询，使用-&gt;或者-&gt;&gt;，注意两个区别（附1）</span>
<span class="hljs-keyword">select</span> json_data<span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span>&quot;$.name&quot; <span class="hljs-keyword">as</span> name <span class="hljs-keyword">from</span> t_json;
<span class="hljs-operator">+</span><span class="hljs-comment">--------+</span>
<span class="hljs-operator">|</span> name   <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-comment">--------+</span>
<span class="hljs-operator">|</span> &quot;abul&quot; <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-comment">--------+</span>

<span class="hljs-keyword">select</span> json_data<span class="hljs-operator">-</span><span class="hljs-operator">&gt;&gt;</span>&quot;$.name&quot; <span class="hljs-keyword">as</span> name <span class="hljs-keyword">from</span> t_json;
<span class="hljs-operator">+</span><span class="hljs-comment">------+</span>
<span class="hljs-operator">|</span> name <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-comment">------+</span>
<span class="hljs-operator">|</span> abul <span class="hljs-operator">|</span>
<span class="hljs-operator">+</span><span class="hljs-comment">------+</span>

<span class="hljs-comment">-- 根据json里的字段模糊搜索，其余操作相同</span>
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> t_json <span class="hljs-keyword">where</span> json_data<span class="hljs-operator">-</span><span class="hljs-operator">&gt;&gt;</span>&quot;$.name&quot; <span class="hljs-keyword">like</span> <span class="hljs-string">&#x27;ab%&#x27;</span>;

<span class="hljs-comment">-- 变更某个key值</span>
update t_json <span class="hljs-keyword">set</span> json_data<span class="hljs-operator">=</span>json_replace(json_data,<span class="hljs-string">&#x27;$.name&#x27;</span>,<span class="hljs-string">&#x27;xmabul&#x27;</span>) <span class="hljs-keyword">where</span> id<span class="hljs-operator">=</span><span class="hljs-number">1</span>;

<span class="hljs-comment">-- 创建虚拟列和索引</span>
<span class="hljs-comment">-- 场景：json某个key为高频查询，需要创建key对应索引</span>
<span class="hljs-keyword">create</span> <span class="hljs-keyword">table</span> t_json_index(
  id <span class="hljs-type">int</span> unsigned <span class="hljs-keyword">not</span> <span class="hljs-keyword">null</span> auto_increment,
  json_data json <span class="hljs-keyword">null</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">null</span> comment <span class="hljs-string">&#x27;json类型字段&#x27;</span>,
  name <span class="hljs-type">varchar</span>(<span class="hljs-number">20</span>) generated always <span class="hljs-keyword">as</span> (json_data<span class="hljs-operator">-</span><span class="hljs-operator">&gt;&gt;</span>&quot;$.name&quot;) comment <span class="hljs-string">&#x27;json.name&#x27;</span>,  <span class="hljs-comment">-- 虚拟列</span>
  <span class="hljs-keyword">primary</span> key(id),
  index idx_name(name)   <span class="hljs-comment">-- 虚拟列索引</span>
)comment <span class="hljs-string">&#x27;创建json类型表索引&#x27;</span>;

<span class="hljs-comment">-- 判断指定值是否在json数组中</span>
<span class="hljs-keyword">where</span> json_contains(clear_rule_json,<span class="hljs-built_in">json_object</span>(&quot;typeEnum&quot;,<span class="hljs-string">&#x27;MERCHANT_GET&#x27;</span>))


<span class="hljs-comment">-- json函数</span>
<span class="hljs-comment">-- 详细文档：https://dev.mysql.com/doc/refman/5.7/en/json-function-reference.html</span>
<span class="hljs-operator">-</span><span class="hljs-operator">&gt;</span>										等价于JSON_EXTRACT().		
<span class="hljs-operator">-</span><span class="hljs-operator">&gt;&gt;</span>										等价于JSON_UNQUOTE(JSON_EXTRACT())	
<span class="hljs-built_in">JSON_ARRAY</span>()					创建一个数组
JSON_ARRAY_APPEND()		扩展json数组对象		
JSON_ARRAY_INSERT()		在指定数组位置插入值 
JSON_CONTAINS()				判断指定值是否在json文档中		
JSON_CONTAINS_PATH()	判断是否包含路径	
JSON_DEPTH()					返回最深层级		
JSON_EXTRACT()				解析json，返回<span class="hljs-keyword">value</span>值		
JSON_INSERT()					插入值		
JSON_KEYS()						返回所有key		
JSON_LENGTH()					返回json元素个数		
JSON_MERGE()					json合并
JSON_MERGE_PATCH()		合并json，替换重复key值	
JSON_MERGE_PRESERVE()	json合并，相同key合并值	
<span class="hljs-built_in">JSON_OBJECT</span>()					创建一个object对象		
JSON_PRETTY()					美化json对象
JSON_QUOTE()					添加引号		
JSON_REMOVE()					移除json中的某个key		
JSON_REPLACE()				替换json某个key值		
JSON_SEARCH()					查找值对应路径		
JSON_SET()						插入key值，相当于replace <span class="hljs-keyword">into</span>		
JSON_STORAGE_SIZE()		返回存储json文档的二进制的字节数
JSON_TYPE()						返回类型		
JSON_UNQUOTE()				取消引号		
JSON_VALID()					判断json是否合法		
</code></pre>
<p>附：</p>
<ol>
<li>-&gt;和-&gt;&gt;区别
mysql 5.7.9开始支持-&gt; ;mysql5.7.13开始支持-&gt;&gt;<br>-&gt;等价于JSON_EXTRACT()，将json拆解，如果是字符串会包含引号
-&gt;&gt;等价于JSON_UNQUOTE()，将json拆解，并且去掉引号</li>
</ol>
<h2><a id="toc-5d2" class="anchor" href="#toc-5d2"></a>三、建议</h2>
<ol>
<li>如果存储的json数据长度小于1000，并且不需要通过json文档里的key进行查询过滤，建议直接定义varchar类型，减少占用空间。</li>
<li>如果需要根据键值查询，可以定义成json；但是当需要存储大字段时，还是建议存储到mongodb中，专业的存储引擎做专业的事。</li>
</ol>
<p>原则上json数据存储建议 <strong>mongodb &gt; mysql.varchar &gt; mysql.json</strong></p>

            ]]></description>
            <pubDate>Fri, 06 Jan 2023 12:54:17 GMT</pubDate>
            <guid>http://www.tusundong.top/post/mysql_json.html</guid>
        </item>
        <item>
            <title>MySQL内存计算</title>
            <link>http://www.tusundong.top/post/MySQL-nei-cun-ji-suan.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-dd4">1. 最大可使用内存（ M ）：</a></li>
<li><a href="#toc-2bc">2.单个连接最大可使用内存（ M ）：</a></li>
<li><a href="#toc-09b">3.最大可使用内存（不包含连接占用内存）（ M ）：</a></li>
</ul>
</div><h3><a id="toc-dd4" class="anchor" href="#toc-dd4"></a>1. 最大可使用内存（ M ）：</h3>
<pre><code class="hljs lang-sql"><span class="hljs-keyword">SELECT</span> 
  (
    @<span class="hljs-variable">@key</span>_buffer_size <span class="hljs-operator">+</span> 
    @<span class="hljs-variable">@query</span>_cache_size <span class="hljs-operator">+</span> 
    @<span class="hljs-variable">@tmp</span>_table_size <span class="hljs-operator">+</span> 
    @<span class="hljs-variable">@innodb</span>_buffer_pool_size  <span class="hljs-operator">+</span> 
    @<span class="hljs-variable">@innodb</span>_log_buffer_size <span class="hljs-operator">+</span> 
    @<span class="hljs-variable">@max</span>_connections <span class="hljs-operator">*</span> (
        @<span class="hljs-variable">@sort</span>_buffer_size <span class="hljs-operator">+</span> 
        @<span class="hljs-variable">@read</span>_buffer_size <span class="hljs-operator">+</span> 
        @<span class="hljs-variable">@read</span>_rnd_buffer_size <span class="hljs-operator">+</span> 
        @<span class="hljs-variable">@join</span>_buffer_size <span class="hljs-operator">+</span> 
        @<span class="hljs-variable">@binlog</span>_cache_size <span class="hljs-operator">+</span> 
        @<span class="hljs-variable">@thread</span>_stack
    )
  ) <span class="hljs-operator">/</span> <span class="hljs-number">1024</span> <span class="hljs-operator">/</span> <span class="hljs-number">1024</span>  <span class="hljs-keyword">as</span> `MaxMem(M)` ;
</code></pre>
<h3><a id="toc-2bc" class="anchor" href="#toc-2bc"></a>2.单个连接最大可使用内存（ M ）：</h3>
<pre><code class="hljs lang-sql">  <span class="hljs-keyword">SELECT</span> 
 (
     @<span class="hljs-variable">@sort</span>_buffer_size <span class="hljs-operator">+</span> 
     @<span class="hljs-variable">@read</span>_buffer_size <span class="hljs-operator">+</span> 
     @<span class="hljs-variable">@read</span>_rnd_buffer_size <span class="hljs-operator">+</span> 
     @<span class="hljs-variable">@join</span>_buffer_size <span class="hljs-operator">+</span> 
     @<span class="hljs-variable">@binlog</span>_cache_size <span class="hljs-operator">+</span> 
     @<span class="hljs-variable">@thread</span>_stack
 ) <span class="hljs-operator">/</span> <span class="hljs-number">1024</span> <span class="hljs-operator">/</span> <span class="hljs-number">1024</span> <span class="hljs-keyword">AS</span> `ConnectMem(M)` ;
</code></pre>
<h3><a id="toc-09b" class="anchor" href="#toc-09b"></a>3.最大可使用内存（不包含连接占用内存）（ M ）：</h3>
<pre><code class="hljs lang-less">   <span class="hljs-selector-tag">SELECT</span> 
     (
   <span class="hljs-variable">@@key_buffer_size</span> + 
   <span class="hljs-variable">@@query_cache_size</span> + 
   <span class="hljs-variable">@@tmp_table_size</span> + 
   <span class="hljs-variable">@@innodb_buffer_pool_size</span>  + 
   <span class="hljs-variable">@@innodb_log_buffer_size</span>
     ) / <span class="hljs-selector-tag">1024</span> / <span class="hljs-selector-tag">1024</span> <span class="hljs-selector-tag">AS</span> `<span class="hljs-selector-tag">MaxMemExcCon</span>(M)`;
</code></pre>

            ]]></description>
            <pubDate>Wed, 21 Dec 2022 02:45:10 GMT</pubDate>
            <guid>http://www.tusundong.top/post/MySQL-nei-cun-ji-suan.html</guid>
        </item>
        <item>
            <title>postman动态设置token</title>
            <link>http://www.tusundong.top/post/postman-dong-tai-she-zhi-token.html</link>
            <description><![CDATA[
            <div class="toc"></div><p>Postman下载地址：<a href="https://www.postman.com/">https://www.postman.com/</a></p>
<ol>
<li><p>配置Environments
<img src="https://www.tusundong.top/static/upload/20221021/upload_0df1ba060e9735542bc836f1effbc245.png" alt="image.png"><br>只需设置变量名，如Authorization，其它列不用配置。</p>
</li>
<li><p>登录，设置Test<br><img src="https://www.tusundong.top/static/upload/20221021/upload_40ff738e5ef2158b4cafbf8e9b84754d.png" alt="image.png">
<img src="https://www.tusundong.top/static/upload/20221021/upload_00d1660f565feee3f97d25c19d93c5ca.png" alt="image.png"><br>登录成功后，变量马上有值，可查看如下：
<img src="https://www.tusundong.top/static/upload/20221021/upload_e601614790c3986a2057e84537759ab1.png" alt="image.png"></p>
<blockquote>
<p>使用老版本postman可能会报错，<code>pm is not defined</code>。</p>
</blockquote>
</li>
<li><p>其它接口调用token
<img src="https://www.tusundong.top/static/upload/20221021/upload_b694ece2c4469cd7dad42c4c162bcb6b.png" alt="image.png"></p>
</li>
</ol>

            ]]></description>
            <pubDate>Fri, 21 Oct 2022 07:29:15 GMT</pubDate>
            <guid>http://www.tusundong.top/post/postman-dong-tai-she-zhi-token.html</guid>
        </item>
        <item>
            <title>MySQL全文索引-ngram中文模糊搜索</title>
            <link>http://www.tusundong.top/post/MySQL-quan-wen-suo-yin--ngram-zhong-wen-mo-hu-sou-suo.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-735">创建全文索引</a></li>
<li><a href="#toc-ecf">使用</a></li>
<li><a href="#toc-138">注意</a></li>
</ul>
</div><p>说明：本文仅临时备注下，详情自行阅读官网：<a href="https://dev.mysql.com/doc/refman/5.7/en/fulltext-search-ngram.html">https://dev.mysql.com/doc/refman/5.7/en/fulltext-search-ngram.html</a></p>
<p>版本要求：MySQL 5.7.6后内置ngram全文解析器，用来支持中日韩分词。  </p>
<pre><code class="hljs lang-asciidoc"># 查看当前mysql是否支持（有返回结果说明支持，值为2表示检索的字符至少要2个）
<span class="hljs-section">root test&gt;show global variables like &#x27;ngram_token_size&#x27;;
+------------------+-------+</span>
<span class="hljs-section">| Variable_name    | Value |
+------------------+-------+</span>
<span class="hljs-section">| ngram_token_size | 2     |
+------------------+-------+</span>
1 row in set (0.00 sec)
</code></pre>
<h3><a id="toc-735" class="anchor" href="#toc-735"></a>创建全文索引</h3>
<p>语法：<code>FULLTEXT (列名,列名,...) WITH PARSER ngram</code></p>
<pre><code class="hljs lang-sql"># 建表时创建全文索引
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> articles (
      id <span class="hljs-type">INT</span> UNSIGNED AUTO_INCREMENT <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">PRIMARY</span> KEY,
      title <span class="hljs-type">VARCHAR</span>(<span class="hljs-number">200</span>),
      body TEXT,
      FULLTEXT (title,body) <span class="hljs-keyword">WITH</span> PARSER ngram
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> utf8mb4;

# 建表后新增
<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> articles <span class="hljs-keyword">ADD</span> FULLTEXT INDEX ft_title(title) <span class="hljs-keyword">with</span> parser ngram;
</code></pre>
<h3><a id="toc-ecf" class="anchor" href="#toc-ecf"></a>使用</h3>
<p>全文检索模式<br>常用的全文检索模式有两种：  </p>
<ol>
<li>自然语言模式(NATURAL LANGUAGE MODE)   - <strong>默认</strong><br>自然语言模式是MySQL 默认的全文检索模式。自然语言模式不能使用操作符，不能指定关键词必须出现或者必须不能出现等复杂查询。  </li>
<li>BOOLEAN模式(BOOLEAN MODE) - <strong>完全匹配</strong><br>BOOLEAN模式可以使用操作符，可以支持指定关键词必须出现或者必须不能出现或者关键词的权重高还是低等复杂查询。</li>
</ol>
<p>之前使用的时候没注意到还有boolean模式，导致之前使用全文索引发现搜索出不相关的结果，就放弃了，今天重新测试，使用boolean可以符合要求，如下。</p>
<pre><code class="hljs lang-sql"># 搜索的字符前添加<span class="hljs-operator">+</span>，表示必须包含，后面添加<span class="hljs-keyword">IN</span> <span class="hljs-type">BOOLEAN</span> MODE
<span class="hljs-keyword">SELECT</span> id,title,body
<span class="hljs-keyword">FROM</span> articles
<span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">MATCH</span> (title) AGAINST (<span class="hljs-string">&#x27;+手机&#x27;</span> <span class="hljs-keyword">IN</span> <span class="hljs-type">BOOLEAN</span> MODE) ;
</code></pre>
<p>BOOLEAN模式下运算符的使用方式：</p>
<pre><code class="hljs lang-pgsql"><span class="hljs-string">&#x27;apple banana&#x27;</span> 
无操作符，表示或，要么包含apple，要么包含banana

<span class="hljs-string">&#x27;+apple +juice&#x27;</span>
必须同时包含两个词

<span class="hljs-string">&#x27;+apple macintosh&#x27;</span>
必须包含apple，但是如果也包含macintosh的话，相关性会更高。

<span class="hljs-string">&#x27;+apple -macintosh&#x27;</span>
必须包含apple，同时不能包含macintosh。

<span class="hljs-string">&#x27;+apple ~macintosh&#x27;</span>
必须包含apple，但是如果也包含macintosh的话，相关性要比不包含macintosh的记录低。

<span class="hljs-string">&#x27;+apple +(&gt;juice &lt;pie)&#x27;</span>
查询必须包含apple和juice或者apple和pie的记录，但是apple juice的相关性要比apple pie高。

<span class="hljs-string">&#x27;apple*&#x27;</span>
查询包含以apple开头的单词的记录，如apple、apples、applet。

<span class="hljs-string">&#x27;&quot;some words&quot;&#x27;</span>
使用双引号把要搜素的词括起来，效果类似于<span class="hljs-keyword">like</span> <span class="hljs-string">&#x27;%some words%&#x27;</span>，
例如“<span class="hljs-keyword">some</span> words <span class="hljs-keyword">of</span> wisdom”会被匹配到，而“<span class="hljs-keyword">some</span> noise words”就不会被匹配。
</code></pre>
<h3><a id="toc-138" class="anchor" href="#toc-138"></a>注意</h3>
<ul>
<li>只能在类型为CHAR、VARCHAR或者TEXT的字段上创建全文索引。  </li>
<li>全文索引只支持InnoDB和MyISAM引擎。</li>
<li>MATCH (columnName) AGAINST (&#39;keywords&#39;)。<br>MATCH()函数使用的字段名，必须要与创建全文索引时指定的字段名一致。如上面的示例，MATCH (title,body)使用的字段名与全文索引ft_articles(title,body)定义的字段名一致。如果要对title或者body字段分别进行查询，就需要在title和body字段上分别创建新的全文索引。</li>
<li>MATCH()函数使用的字段名只能是同一个表的字段，因为全文索引不能够跨多个表进行检索。</li>
<li>如果要导入大数据集，使用先导入数据再在表上创建全文索引的方式要比先在表上创建全文索引再导入数据的方式快很多，所以全文索引是很影响TPS的。</li>
</ul>

            ]]></description>
            <pubDate>Tue, 11 Oct 2022 07:10:19 GMT</pubDate>
            <guid>http://www.tusundong.top/post/MySQL-quan-wen-suo-yin--ngram-zhong-wen-mo-hu-sou-suo.html</guid>
        </item>
        <item>
            <title>MySQL开发规范</title>
            <link>http://www.tusundong.top/post/MySQL-standard.html</link>
            <description><![CDATA[
            <div class="toc"><ul>
<li><a href="#toc-615">MySQL开发规范</a><ul>
<li><a href="#toc-8ed">一、命名规范</a></li>
<li><a href="#toc-b83">二、建表规范</a></li>
<li><a href="#toc-9da">三、索引规范</a></li>
<li><a href="#toc-e27">四、SQL规范</a></li>
</ul>
</li>
</ul>
</div><h2><a id="toc-615" class="anchor" href="#toc-615"></a>MySQL开发规范</h2>
<h3><a id="toc-8ed" class="anchor" href="#toc-8ed"></a>一、命名规范</h3>
<ol>
<li>命名要见名知意，全部使用小写字母，多个单词之间使用下划线连接<blockquote>
<p>禁止使用中文拼音！  </p>
</blockquote>
<p>例：<code>t_article_detail</code></p>
</li>
<li>database<br>db_[数据库名]<br>例如：<code>db_hms</code></li>
<li>table<br>t_[表名]<br>例如：<code>t_school</code></li>
<li>index<br>idx_[普通索引]、uk_[唯一索引]<br>例如：<code>idx_uid</code>、<code>uk_record_id</code></li>
<li>view<br>v_[视图名]</li>
<li><del>function（默认禁止使用）</del><br>f_[方法名]</li>
<li><del>procedure（默认禁止使用）</del><br>p_[存储过程名]</li>
<li><del>event（默认禁止使用）</del><br>e_[事件名]</li>
</ol>
<h3><a id="toc-b83" class="anchor" href="#toc-b83"></a>二、建表规范</h3>
<ol>
<li><p>所有列名、表名都要有注释</p>
</li>
<li><p>字符集统一使用utf8mb4，排序规则使用utf8mb4_general_ci（特殊例外）<br>排序规则默认使用utf8mb4_general_ci，列值如果需要根据大小写过滤则配置对应列排序规则为utf8mb4_bi，如验证码、密码</p>
</li>
</ol>
<pre><code class="hljs lang-sql">### 字符集使用utf8mb4，默认使用utf8mb4_general_ci
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> t_test (
 id <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;自增id&#x27;</span>,
 val <span class="hljs-type">varchar</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-string">&#x27;&#x27;</span> COMMENT <span class="hljs-string">&#x27;值&#x27;</span>,
 <span class="hljs-keyword">PRIMARY</span> KEY (`id`)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;测试表&#x27;</span>;

### 特殊列需要根据大小写过滤，配置列排序规则utf8mb4_bin
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `t_test` (
 id <span class="hljs-type">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;自增id&#x27;</span>,
 pwd <span class="hljs-type">varchar</span>(<span class="hljs-number">20</span>) <span class="hljs-type">CHARACTER</span> <span class="hljs-keyword">SET</span> utf8mb4 <span class="hljs-keyword">COLLATE</span> utf8mb4_bin <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-string">&#x27;&#x27;</span> COMMENT <span class="hljs-string">&#x27;密码&#x27;</span>,
 <span class="hljs-keyword">PRIMARY</span> KEY (`id`)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT<span class="hljs-operator">=</span><span class="hljs-string">&#x27;测试表&#x27;</span>;
</code></pre>
<ol start="3">
<li><p>字段名禁止使用数据库保留关键字<br>例如：<code>date</code>、<code>datetime</code>、<code>desc</code>、<code>range</code>、<code>match</code>、<code>comment</code>、<code>add</code>等<br>所有MySQL保留关键字详见 <a href="https://dev.mysql.com/doc/refman/5.7/en/keywords.html#keywords-in-current-series">mysql5.7关键字和保留字</a></p>
</li>
<li><p>表的主键的命名建议依据表的含义+_id<br>例如：用户表t_user 主键为user_id  </p>
</li>
<li><p>新建表需要创建字段<br>【必选】创建时间<code>create_time</code> ,修改时间 <code>update_time</code>；【可选】是否可用 <code>is_flag</code></p>
</li>
</ol>
<pre><code class="hljs lang-sql"> <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `t_test` (
  `id` <span class="hljs-type">bigint</span>(<span class="hljs-number">20</span>) UNSIGNED <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;自增id&#x27;</span>,
  `is_flag` tinyint(<span class="hljs-number">2</span>) unsigned <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-string">&#x27;1&#x27;</span> COMMENT <span class="hljs-string">&#x27;是否可用，1是，0否&#x27;</span>,
  `create_time` datetime <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;创建时间&#x27;</span>,
  `update_time` datetime <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-built_in">CURRENT_TIMESTAMP</span> <span class="hljs-keyword">ON</span> UPDATE <span class="hljs-built_in">CURRENT_TIMESTAMP</span> COMMENT <span class="hljs-string">&#x27;更新时间&#x27;</span>,
  <span class="hljs-keyword">PRIMARY</span> KEY (`id`)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT <span class="hljs-string">&#x27;测试表&#x27;</span>
;
</code></pre>
<ol start="6">
<li>每个表都需要有主键，自增主键使用unsigned<br>建议使用自增键作为主键，避免使用uuid、字符串等做主键，禁止无主键  </li>
<li>小数类型使用 decimal ，禁止使用 float 和 double<br>说明：float 和 double 在存储的时候,存在精度损失的问题。decimal(M,D)，M表示总位数，D表示小数点后位数；<br>例如：decimal(5,2)，整数部分可以存储3位，小数部分可以存储2位</li>
<li>数值类型的字段只有正数时，指定unsigned</li>
</ol>
<pre><code class="hljs lang-sql"> <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> `t_test` (
  `id` <span class="hljs-type">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> AUTO_INCREMENT COMMENT <span class="hljs-string">&#x27;自增id&#x27;</span>,
  `age` tinyint(<span class="hljs-number">3</span>) unsigned <span class="hljs-keyword">NOT</span> <span class="hljs-keyword">NULL</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-string">&#x27;0&#x27;</span> COMMENT <span class="hljs-string">&#x27;只有正数，指定unsigned&#x27;</span>
  <span class="hljs-keyword">PRIMARY</span> KEY (`id`)
) ENGINE<span class="hljs-operator">=</span>InnoDB <span class="hljs-keyword">DEFAULT</span> CHARSET<span class="hljs-operator">=</span>utf8mb4 COMMENT <span class="hljs-string">&#x27;测试表&#x27;</span>
;
</code></pre>
<ol start="9">
<li>存储货币，类型使用整型，单位为分</li>
<li>字段设置默认值，尽量避免空值null</li>
<li>表之间的关联字段，字段类型和字符集要保持一致</li>
</ol>
<pre><code class="hljs lang-sql">#t_class的id和t_student的class_id关联，两者的字段类型和字符集要一致
<span class="hljs-keyword">select</span> t_class.<span class="hljs-operator">*</span>,t_student.<span class="hljs-operator">*</span> 
<span class="hljs-keyword">from</span> t_student  
 <span class="hljs-keyword">left</span> <span class="hljs-keyword">join</span> t_class <span class="hljs-keyword">on</span> t_class.id<span class="hljs-operator">=</span>t_student.class_id;
</code></pre>
<ol start="12">
<li>表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是<code>unsigned tinyint</code>( 1 表示是,0 表示否 ) 。<br>说明:任何字段如果为非负数,必须是<code>unsigned</code>。<br>例如:表达逻辑删除的字段名 is_deleted ,1 表示删除,0 表示未删除。</li>
<li>varchar长度限制<br>建议不要超过5000，如果存储长度大于此值，定义字段类型为 text，独立出来一张表，用主键来关联，避免影响其它字段索引效率。</li>
<li>删除自增初始值<br>说明：有的表结构通过测试环境导出，会含有AUTO_INCREMENT=N，请将其删除再提交。</li>
<li>修改同一张多个字段，合并为单条SQL<br>说明：经常有同事对同一张表添加多个字段，分成多条SQL，带来的影响是每执行一条DDL都会对该表重建和锁表。</li>
</ol>
<pre><code class="hljs lang-sql">#反例，添加t_task多个字段
<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> t_task <span class="hljs-keyword">ADD</span> identity_type  tinyint(<span class="hljs-number">4</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-string">&#x27;1&#x27;</span> COMMENT <span class="hljs-string">&#x27;用户身份类型: 非会员:0、全员:1、白银会员:2、超级会员:3;&#x27;</span>;
<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> t_task <span class="hljs-keyword">ADD</span> online_time <span class="hljs-type">date</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;上线时间 格式： YYYY-MM-DD&#x27;</span>;
<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> t_task <span class="hljs-keyword">ADD</span> offline_time <span class="hljs-type">date</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;下线时间 格式： YYYY-MM-DD&#x27;</span>;

#正例
<span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> t_task 
  <span class="hljs-keyword">ADD</span> identity_type  tinyint(<span class="hljs-number">4</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-string">&#x27;1&#x27;</span> COMMENT <span class="hljs-string">&#x27;用户身份类型: 非会员:0、全员:1、白银会员:2、超级会员:3;&#x27;</span>,
  <span class="hljs-keyword">ADD</span> online_time <span class="hljs-type">date</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;上线时间 格式： YYYY-MM-DD&#x27;</span>,
  <span class="hljs-keyword">ADD</span> offline_time <span class="hljs-type">date</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">NULL</span> COMMENT <span class="hljs-string">&#x27;下线时间 格式： YYYY-MM-DD&#x27;</span>;
</code></pre>
<ol start="16">
<li><p>有限类型选项，选择【够用】类型<br>说明：不同类型取值范围不一样，有的字段取值就0、1、2，10以内，字段类型可选择为tinyint  </p>
<table>
<thead>
<tr>
<th>类型</th>
<th>取值范围（有符号）</th>
<th>取值范围（无符号）</th>
</tr>
</thead>
<tbody><tr>
<td>tinyint</td>
<td>-128~127</td>
<td>0~255</td>
</tr>
<tr>
<td>smallint</td>
<td>-32768~32767</td>
<td>0~65535</td>
</tr>
<tr>
<td>mediumint</td>
<td>-8388608~8388607</td>
<td>0~16777215</td>
</tr>
<tr>
<td>int</td>
<td>-2147483648~2147483647</td>
<td>0~4294967295</td>
</tr>
</tbody></table>
</li>
<li><p>禁止使用外键</p>
</li>
<li><p>基础字段长度标准<br>说明：经常有表需要添加字段【操作人名称】(operation_name/user_name)、图片链接地址(url)等，可按此标准创建（需开发确认），防止字段长度过短被截取或报错。</p>
<table>
<thead>
<tr>
<th>字段</th>
<th>建议长度</th>
<th>备注</th>
</tr>
</thead>
<tbody><tr>
<td>operation_name/user_name</td>
<td>varchar(50)</td>
<td>操作人名称</td>
</tr>
<tr>
<td>url</td>
<td>varchar(200)</td>
<td>图片链接地址</td>
</tr>
</tbody></table>
</li>
<li><p>表限制
列数：单表列数小于30
行数：以三年内的数据量，超过 500 万行或者单表容量超过 2 GB ,建议进行分库分表。  </p>
</li>
<li><p>时间字段类型建议使用datetime，而不是timestamp<br>说明：虽然timestamp占用空间比datetime小，但仅能存储到<code>2038-01-19</code></p>
</li>
<li><p>字段类型tinyint(1)建议更改为tinyint(2)
说明：括号中数字跟存储的大小范围无关，但canal会将tinyint(1)类型解析成bit导致同步错误。</p>
</li>
</ol>
<p><del>22. DRDS分布式事务</del>
<del>drds支持2PC，但在同一个事务里，涉及insert的表都需要创建全局序列Sequence，否则会报错。(目前仅dbfileserver有使用)</del>   </p>
<h3><a id="toc-9da" class="anchor" href="#toc-9da"></a>三、索引规范</h3>
<ol>
<li>索引命名<br>以idx_开头，单个字段为列名全称，组合索引的列名之间通过下划线关联，列名内取消下划线</li>
</ol>
<pre><code class="hljs lang-sql"><span class="hljs-keyword">alter</span> <span class="hljs-keyword">table</span> t_test <span class="hljs-keyword">add</span> index idx_student_id(student_id);  #单个字段，列名全称
<span class="hljs-keyword">alter</span> <span class="hljs-keyword">table</span> t_test <span class="hljs-keyword">add</span> index idx_classid_studentid(class_id,student_id);  #多个字段，列名内取消下划线，列名之间通过下划线关联
</code></pre>
<ol start="2">
<li><p>索引限制
单表索引个数建议在5个以内，单个索引字段不超过5个</p>
</li>
<li><p>禁止左模糊搜索或全模糊搜索</p>
</li>
</ol>
<pre><code class="hljs lang-sql">#正例
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> t_student <span class="hljs-keyword">where</span> name <span class="hljs-keyword">like</span> <span class="hljs-string">&#x27;中%&#x27;</span>;
 
#反例
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> t_student <span class="hljs-keyword">where</span> name <span class="hljs-keyword">like</span> <span class="hljs-string">&#x27;%中&#x27;</span>;
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> t_student <span class="hljs-keyword">where</span> name <span class="hljs-keyword">like</span> <span class="hljs-string">&#x27;%中%&#x27;</span>;
</code></pre>
<ol start="4">
<li>varchar字段建立索引，指定索引长度<br>正常没必要对整个字段建立索引，一般长度20能区分90%数据。<br>varchar长度在50以内，可以直接使用整个字段建立索引，超过50以后使用<code>count(distinct left(列名, 索引长度))/count(*)</code>的区分度来确认索引长度。</li>
</ol>
<pre><code class="hljs lang-sql">#name字段长度为<span class="hljs-number">100</span>
<span class="hljs-keyword">alter</span> <span class="hljs-keyword">table</span> t_test <span class="hljs-keyword">add</span> index idx_name(name(<span class="hljs-number">20</span>));
</code></pre>
<ol start="5">
<li>避免在区分度不高，频繁更新列上建立索引</li>
<li>表数据量在1000以内，可不用建索引</li>
</ol>
<h3><a id="toc-e27" class="anchor" href="#toc-e27"></a>四、SQL规范</h3>
<ol>
<li>尽量使用简单SQL<br>对复杂SQL进行拆分，化简成简单SQL，尽量减少多表关联。</li>
<li>避免在索引列进行运算导致索引失效引发全表扫描</li>
</ol>
<pre><code class="hljs lang-sql">#反例：对列create_time进行date_format运算
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> t_student <span class="hljs-keyword">where</span> date_format(create_time,<span class="hljs-string">&#x27;%Y-%m-%d&#x27;</span>)<span class="hljs-operator">=</span><span class="hljs-string">&#x27;2021-02-24&#x27;</span>;
 
#正例：转换成对值的判断
<span class="hljs-keyword">select</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">from</span> t_student <span class="hljs-keyword">where</span> create_time <span class="hljs-operator">&gt;=</span> <span class="hljs-string">&#x27;2021-02-24&#x27;</span> <span class="hljs-keyword">and</span> create_time <span class="hljs-operator">&lt;</span> <span class="hljs-string">&#x27;2021-02-25&#x27;</span>;
</code></pre>
<ol start="3">
<li>避免使用大事务造成执行锁定时间，同时导致备库只读节点数据延迟</li>
<li>查询时显示指定要查询列，避免直接select *</li>
<li>利用延迟关联或者子查询优化超多分页场景</li>
</ol>
<pre><code class="hljs lang-sql">#原始<span class="hljs-keyword">SQL</span>
<span class="hljs-keyword">SELECT</span> <span class="hljs-operator">*</span> <span class="hljs-keyword">FROM</span> 表<span class="hljs-number">1</span> <span class="hljs-keyword">where</span> 条件 LIMIT <span class="hljs-number">100000</span>,<span class="hljs-number">20</span>;
 
#建议，延迟关联，先查询主键id，再通过关联出所有字段
<span class="hljs-keyword">SELECT</span> a.<span class="hljs-operator">*</span> <span class="hljs-keyword">FROM</span> 表<span class="hljs-number">1</span> a, (<span class="hljs-keyword">select</span> id <span class="hljs-keyword">from</span> 表<span class="hljs-number">1</span> <span class="hljs-keyword">where</span> 条件 LIMIT <span class="hljs-number">100000</span>,<span class="hljs-number">20</span> ) b <span class="hljs-keyword">where</span> a.id<span class="hljs-operator">=</span>b.id;
</code></pre>

            ]]></description>
            <pubDate>Tue, 06 Sep 2022 07:48:00 GMT</pubDate>
            <guid>http://www.tusundong.top/post/MySQL-standard.html</guid>
        </item>
    </channel>
</rss>
