一家团聚 發表於 2023-11-30 00:00:00

书写高质量SQL的建议

<p>
        <img title="书写高质量SQL的建议" alt="书写高质量SQL的建议" border="0" height="auto" src="https://zhuji.jb51.net/uploads/img/202305/27a6211a8225b51da65b6d1e9213b700.jpg" width="auto"></p>
<h3>
        1、避免混乱的逻辑</h3>
<p>
        反例:(统计用户数量)</p>
<ol class="dp-sql">
<li class="alt">
                <span><span>List&lt;</span><span class="func">User</span><span>&gt; users = userMapper.selectAll(); </span></span>
</li>
        <li>
                <span><span class="keyword">return</span><span> users.</span><span class="keyword">size</span><span>(); </span></span>
</li>
</ol>
<p>
        正例:</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">int</span><span> </span><span class="func">count</span><span> = userMapper.countUser(</span><span class="string">"select count(*) from user"</span><span>); </span></span>
</li>
        <li>
                <span><span class="keyword">return</span><span> </span><span class="func">count</span><span>; </span></span>
</li>
</ol>
<h3>
        2、select one 如果已知结果只有一条, 使用limit 1</h3>
<p>
        反例:(查找nickname = 报之琼瑶 的用户)</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span>  id, nickname </span><span class="keyword">from</span><span> t  </span><span class="keyword">where</span><span> nickname = </span><span class="string">'报之琼瑶'</span><span> </span></span>
</li>
</ol>
<p>
        正例:</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span>  id, nickname </span><span class="keyword">from</span><span> t  </span><span class="keyword">where</span><span> nickname = </span><span class="string">'报之琼瑶'</span><span> limit 1 </span></span>
</li>
</ol>
<p>
        理由:</p>
<ol>
<li>
                加上limit1,只要找到了对应的一条记录, 就不会继续向下扫描了,效率会大大提高。limit1适用于查询结果为1条(也可能为0)会导致全表扫描的的SQL语句。</li>
        <li>
                如果条件列上有索引就不用limit 1,如主键查询 id = 1</li>
</ol>
<h3>
        3、尽量避免在where子句中使用or来连接条件</h3>
<p>
        反例:(查找name = 张三 或者 法外狂徒 的用户)</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> id,</span><span class="keyword">name</span><span> </span><span class="keyword">from</span><span> t </span><span class="keyword">where</span><span> </span><span class="keyword">name</span><span> = </span><span class="string">'张三'</span><span> </span><span class="op">or</span><span> </span><span class="keyword">name</span><span> = </span><span class="string">'法外狂徒'</span><span> </span></span>
</li>
</ol>
<p>
        正例:</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> id,</span><span class="keyword">name</span><span> </span><span class="keyword">from</span><span> t </span><span class="keyword">where</span><span> </span><span class="keyword">name</span><span> = </span><span class="string">'张三'</span><span> </span></span>
</li>
        <li>
                <span><span class="keyword">union</span><span> </span><span class="op">all</span><span> </span></span>
</li>
        <li class="alt">
                <span><span class="keyword">select</span><span> id,</span><span class="keyword">name</span><span> </span><span class="keyword">from</span><span> t </span><span class="keyword">where</span><span> </span><span class="keyword">name</span><span> = </span><span class="string">'法外狂徒'</span><span> </span></span>
</li>
</ol>
<p>
        理由:</p>
<p>
        使用or将导致引擎放弃使用索引而进行全表扫描</p>
<h3>
        4、优化like关键字</h3>
<p>
        like常用于模糊查询, 不恰当的编码会导致索引失效</p>
<p>
        反例:</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> userId,</span><span class="keyword">name</span><span> </span><span class="keyword">from</span><span> </span><span class="func">user</span><span> </span><span class="keyword">where</span><span> userId </span><span class="op">like</span><span> </span><span class="string">'%123'</span><span> </span></span>
</li>
</ol>
<p>
        正例:</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> userId,</span><span class="keyword">name</span><span> </span><span class="keyword">from</span><span> </span><span class="func">user</span><span> </span><span class="keyword">where</span><span> userId </span><span class="op">like</span><span> </span><span class="string">'123%'</span><span> </span></span>
</li>
</ol>
<center>
        <img title="书写高质量SQL的建议" alt="书写高质量SQL的建议" src="https://zhuji.jb51.net/uploads/img/202305/d975a74437bc1d399e1c7635869ee571.jpg">
</center>
<p>
        %123, 百分号在前不走索引</p>
<center>
        <img title="书写高质量SQL的建议" alt="书写高质量SQL的建议" src="https://zhuji.jb51.net/uploads/img/202305/acd1562cb47e6e06966ddb0c575a5795.jpg">
</center>
<p>
        123%,百分号在后走索引</p>
<p>
        但是也会存在百分号在后不走索引的情况,mysql的innodb存储引擎最终执行哪种方法都是基于成本计算的, 通过比较全表扫描和二级索引比较再回表查询</p>
<p>
        可以通过</p>
<p>
        INFORMATION_SCHEMA.OPTIMIZER_TRACE来分析查询过程</p>
<center>
        <img title="书写高质量SQL的建议" alt="书写高质量SQL的建议" src="https://zhuji.jb51.net/uploads/img/202305/8487b89390b4a345320d784cd8f18db2.jpg">
</center>
<p>
        trace字段json复制出来即可分析</p>
<h3>
        5、查询SQL尽量不要使用select *,而是select具体字段, 不要返回用不到的任何字段。</h3>
<p>
        反例:(统计用户数量)</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span>  *  </span><span class="keyword">from</span><span>  t   </span></span>
</li>
</ol>
<p>
        正例:</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> id, </span><span class="keyword">name</span><span>, tel </span><span class="keyword">from</span><span> t </span></span>
</li>
</ol>
<p>
        理由:</p>
<ol>
<li>
                妨碍优化器选择更优的执行计划,比如说索引扫描</li>
        <li>
                增删字段可能导致代码崩溃</li>
</ol>
<p>
        6、尽量避免在索引列上使用mysql的内置函数</p>
<p>
        反例:</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> * </span><span class="keyword">from</span><span> </span><span class="func">user</span><span> </span><span class="keyword">where</span><span> date_add(create_time,Interval 5 </span><span class="func">day</span><span>) &gt;=now() </span></span>
</li>
</ol>
<p>
        正例:</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> * </span><span class="keyword">from</span><span> </span><span class="func">user</span><span> </span><span class="keyword">where</span><span> create_time &gt;= date_add(now(), interval - 5 </span><span class="func">day</span><span>) </span></span>
</li>
</ol>
<center>
        <img title="书写高质量SQL的建议" alt="书写高质量SQL的建议" src="https://zhuji.jb51.net/uploads/img/202305/84301c689b1556bbc1d1190b4dc9fe6b.jpg">
</center>
<p>
        不走索引</p>
<center>
        <img title="书写高质量SQL的建议" alt="书写高质量SQL的建议" src="https://zhuji.jb51.net/uploads/img/202305/555839d485185b5581d84b600f93dd24.jpg">
</center>
<p>
        走索引</p>
<h3>
        7、应尽量避免在 where 子句中对字段进行表达式操作,这将导致系统放弃使用索引而进行全表扫</h3>
<p>
        反例: (对字段user_age进行运算操作, 不走索引)</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> * </span><span class="keyword">from</span><span> </span><span class="func">user</span><span> </span><span class="keyword">where</span><span> user_age - 1 = 2 </span></span>
</li>
</ol>
<p>
        正例: (走索引)</p>
<ol class="dp-sql">
<li class="alt">
                <span><span class="keyword">select</span><span> * </span><span class="keyword">from</span><span> </span><span class="func">user</span><span> </span><span class="keyword">where</span><span> user_age = 3 </span></span>
</li>
</ol>
<p>
        原文链接:https://www.toutiao.com/a6992763976006271496/</p>
頁: [1]
查看完整版本: 书写高质量SQL的建议