﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-&lt;table border="0" cellspacing="0" cellpadding="0" style="margin-  left:0px;display:inline;height:30px;"&gt;&lt;tr&gt;&lt;td style="font-weight:bold; font-size:16px; line-  height:30px;"&gt;一年十二月&amp;nbsp谁主春秋&lt;/td&gt;&lt;td style="font-size:14px; line-height:30px;"&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;-随笔分类-Database</title><link>http://www.cppblog.com/qinqing1984/category/21398.html</link><description>关注：操作系统、网络、数据库和安全</description><language>zh-cn</language><lastBuildDate>Mon, 11 May 2020 21:23:27 GMT</lastBuildDate><pubDate>Mon, 11 May 2020 21:23:27 GMT</pubDate><ttl>60</ttl><item><title>Oracle数据类型Number的解析实现</title><link>http://www.cppblog.com/qinqing1984/archive/2020/05/08/217292.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Fri, 08 May 2020 04:23:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2020/05/08/217292.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/217292.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2020/05/08/217292.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/217292.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/217292.html</trackback:ping><description><![CDATA[<strong style="font-size: 13pt;">存储格式</strong><br />
&nbsp;&nbsp;&nbsp;Oracle Number数据类型是变长的，占0~22字节，不像编程语言中的2/4字节整数或4/8字节浮点数，关于它的存储格式与解析，DSI上有详细的描述，如下所示<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/oracle_datatype_number.png" width="678" height="509" alt="" /><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<strong style="font-size: 12pt;">符号位/指数字节</strong>描述如下<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/oracle_datatype_number_signbit_exponent_byte.png" width="678" height="509" alt="" /><br />
&nbsp; &nbsp;<br />
&nbsp; &nbsp;<strong style="font-size: 12pt;">数字字节</strong>描述如下<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/oracle_datatype_number_digits_byte.png" width="678" height="508" alt="" /><br />
&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt;">正数或零值的计算</strong><br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/oracle_datatype_number_positive.png" width="678" height="510" alt="" /><br />
&nbsp; &nbsp;<br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt;">负数值的计算</strong><br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/oracle_datatype_number_negative.png" width="678" height="509" alt="" /><br />
<br />
<strong style="font-size: 13pt;">解析实现</strong><br />
&nbsp; &nbsp;由于Oracle Number的精度高达38位，远超出了基本定长整数或浮点数表达的数值范围，因此解析实际上是大整数/实数的四则运算，为避免造轮子，本文使用了<span style="color: red;"><strong>GMP</strong></span>开源库（<a href="https://gmplib.org/" target="_blank">https://gmplib.org/</a>），用于任意精度的算术运算，操作有符号整数、有理数和浮点数，除了在GMP机器上运行的可用内存所暗示的精度之外，对精度没有实际的限制。解析实现的核心函数是<strong style="font-size: 12pt;">orcl_raw2number</strong><br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;#include&nbsp;&lt;stdio.h&gt;<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;#include&nbsp;&lt;assert.h&gt;<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;#include&nbsp;&lt;gmp.h&gt;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;<span style="color: #0000FF; ">#define</span>&nbsp;MAX_PREC&nbsp;&nbsp;256<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;mpf_t&nbsp;s_base100;<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;mpf_t&nbsp;s_one;<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;<br />
<span style="color: #008080; ">10</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;<span style="color: #800000; font-size: 12pt;"><strong>init_mpf_globals</strong></span>()<br />
<span style="color: #008080; ">11</span>&nbsp;{<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_init_set_ui(s_base100,&nbsp;100);<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_init_set_ui(s_one,&nbsp;1);<br />
<span style="color: #008080; ">14</span>&nbsp;}<br />
<span style="color: #008080; ">15</span>&nbsp;<br />
<span style="color: #008080; ">16</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;<strong style="color: #800000; font-size: 12pt;">clear_mpf_globals</strong><span style="font-size: 12pt;">()</span><br />
<span style="color: #008080; ">17</span>&nbsp;{<br />
<span style="color: #008080; ">18</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(s_base100);<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(s_one);<br />
<span style="color: #008080; ">20</span>&nbsp;}<br />
<span style="color: #008080; ">21</span>&nbsp;<br />
<span style="color: #008080; ">22</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;<strong style="font-size: 12pt; color: #800000;">orcl_raw2number</strong>(unsigned&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*data,&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;len,&nbsp;mpf_t&nbsp;result)<br />
<span style="color: #008080; ">23</span>&nbsp;{<br />
<span style="color: #008080; ">24</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;sign&nbsp;=&nbsp;*data,&nbsp;digit,&nbsp;i;<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;exp&nbsp;=&nbsp;sign&gt;=128&nbsp;?&nbsp;sign-193&nbsp;:&nbsp;62-sign;<br />
<span style="color: #008080; ">26</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;exp_val;<br />
<span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_t&nbsp;tmp;<br />
<span style="color: #008080; ">28</span>&nbsp;<br />
<span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_init2(tmp,&nbsp;MAX_PREC);<br />
<span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_init2(result,&nbsp;MAX_PREC);<br />
<span style="color: #008080; ">31</span>&nbsp;<br />
<span style="color: #008080; ">32</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(sign&nbsp;&amp;&nbsp;0x80){<br />
<span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(i=1;&nbsp;i&lt;len;&nbsp;++i){<br />
<span style="color: #008080; ">34</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;digit&nbsp;=&nbsp;data[i]&nbsp;-&nbsp;1;<br />
<span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(0&lt;=digit&nbsp;&amp;&amp;&nbsp;digit&lt;=99);<br />
<span style="color: #008080; ">36</span>&nbsp;<br />
<span style="color: #008080; ">37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exp_val&nbsp;=&nbsp;exp&nbsp;-&nbsp;i&nbsp;+&nbsp;1;<br />
<span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(exp_val&nbsp;&lt;&nbsp;0){&nbsp;<br />
<span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_pow_ui(tmp,&nbsp;s_base100,&nbsp;-exp_val);<br />
<span style="color: #008080; ">40</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_div(tmp,&nbsp;s_one,&nbsp;tmp);&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span><br />
<span style="color: #008080; ">42</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_pow_ui(tmp,&nbsp;s_base100,&nbsp;exp_val);<br />
<span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_mul_ui(tmp,&nbsp;tmp,&nbsp;digit);<br />
<span style="color: #008080; ">45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_add(result,&nbsp;result,&nbsp;tmp);<br />
<span style="color: #008080; ">46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">48</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span>{<br />
<span style="color: #008080; ">49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;--len;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">ignore&nbsp;the&nbsp;last&nbsp;byte</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">50</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">for</span>(i=1;&nbsp;i&lt;len;&nbsp;++i){<br />
<span style="color: #008080; ">51</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;digit&nbsp;=&nbsp;101&nbsp;-&nbsp;data[i];<br />
<span style="color: #008080; ">52</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(0&lt;=digit&nbsp;&amp;&amp;&nbsp;digit&lt;=99);<br />
<span style="color: #008080; ">53</span>&nbsp;<br />
<span style="color: #008080; ">54</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exp_val&nbsp;=&nbsp;exp&nbsp;-&nbsp;i&nbsp;+&nbsp;1;<br />
<span style="color: #008080; ">55</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>(exp_val&nbsp;&lt;&nbsp;0){&nbsp;<br />
<span style="color: #008080; ">56</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_pow_ui(tmp,&nbsp;s_base100,&nbsp;-exp_val);<br />
<span style="color: #008080; ">57</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_div(tmp,&nbsp;s_one,&nbsp;tmp);&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">58</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<span style="color: #0000FF; ">else</span><br />
<span style="color: #008080; ">59</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_pow_ui(tmp,&nbsp;s_base100,&nbsp;exp_val);<br />
<span style="color: #008080; ">60</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">61</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_mul_ui(tmp,&nbsp;tmp,&nbsp;digit);<br />
<span style="color: #008080; ">62</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_add(result,&nbsp;result,&nbsp;tmp);<br />
<span style="color: #008080; ">63</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">64</span>&nbsp;<br />
<span style="color: #008080; ">65</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_neg(result,&nbsp;result);<br />
<span style="color: #008080; ">66</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<span style="color: #008080; ">67</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">68</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(tmp);<br />
<span style="color: #008080; ">69</span>&nbsp;}</div>
<strong style="font-size: 13pt;"><br />
测试用例<br />
</strong>&nbsp;&nbsp;&nbsp;测试了123456.789、-123456.789、Oracle Number实际最大最小值、Oracle Number理论最大最小值<br />
<div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #008080; ">&nbsp;1</span>&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;<span style="color: #800000; font-size: 13pt;"><strong>main</strong></span><span style="color: #0000FF; ">(int</span>&nbsp;argc,&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;*argv[])<br />
<span style="color: #008080; ">&nbsp;2</span>&nbsp;{<br />
<span style="color: #008080; ">&nbsp;3</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">int</span>&nbsp;n&nbsp;=&nbsp;19;<br />
<span style="color: #008080; ">&nbsp;4</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;buf[256];<br />
<span style="color: #008080; ">&nbsp;5</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_t&nbsp;r;<br />
<span style="color: #008080; ">&nbsp;6</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;7</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="color: #800000;">init_mpf_globals</strong>();<br />
<span style="color: #008080; ">&nbsp;8</span>&nbsp;<br />
<span style="color: #008080; ">&nbsp;9</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">123456.789</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">10</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;data[]&nbsp;=&nbsp;{0xc3,0xd,0x23,0x39,0x4f,0x5b};&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">11</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #800000;"><strong>orcl_raw2number</strong></span>(data,&nbsp;<span style="color: #0000FF; ">sizeof</span>(data),&nbsp;r);<br />
<span style="color: #008080; ">12</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gmp_snprintf(buf,&nbsp;<span style="color: #0000FF; ">sizeof</span>(buf),&nbsp;"%Ff\n\t%.*Ff(%d&nbsp;digits)",&nbsp;r,&nbsp;n,&nbsp;r,&nbsp;n);<br />
<span style="color: #008080; ">13</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("result:&nbsp;%s\n",&nbsp;buf);<br />
<span style="color: #008080; ">14</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("\t");&nbsp;mpf_out_str(NULL,&nbsp;10,&nbsp;0,&nbsp;r);&nbsp;printf("\n");<br />
<span style="color: #008080; ">15</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(r);<br />
<span style="color: #008080; ">16</span>&nbsp;<br />
<span style="color: #008080; ">17</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">-123456.789</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">18</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;data2[]&nbsp;=&nbsp;{0x3c,0x59,0x43,0x2d,0x17,0xb,0x66};<br />
<span style="color: #008080; ">19</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="color: #800000;">orcl_raw2number</strong>(data2,&nbsp;<span style="color: #0000FF; ">sizeof</span>(data2),&nbsp;r);<br />
<span style="color: #008080; ">20</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gmp_snprintf(buf,&nbsp;<span style="color: #0000FF; ">sizeof</span>(buf),&nbsp;"%Ff\n\t%.*Ff(%d&nbsp;digits)",&nbsp;r,&nbsp;n,&nbsp;r,&nbsp;n);<br />
<span style="color: #008080; ">21</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("result:&nbsp;%s\n",&nbsp;buf);<br />
<span style="color: #008080; ">22</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("\t");&nbsp;mpf_out_str(NULL,&nbsp;10,&nbsp;0,&nbsp;r);&nbsp;printf("\n");<br />
<span style="color: #008080; ">23</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(r);<br />
<span style="color: #008080; ">24</span>&nbsp;<br />
<span style="color: #008080; ">25</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">0</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">26</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;zero[]&nbsp;=&nbsp;{0x80};<br />
<span style="color: #008080; ">27</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="color: #800000;">orcl_raw2number</strong>(zero,&nbsp;<span style="color: #0000FF; ">sizeof</span>(zero),&nbsp;r);<br />
<span style="color: #008080; ">28</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gmp_snprintf(buf,&nbsp;<span style="color: #0000FF; ">sizeof</span>(buf),&nbsp;"%Ff\n\t%.*Ff(%d&nbsp;digits)",&nbsp;r,&nbsp;n,&nbsp;r,&nbsp;n);<br />
<span style="color: #008080; ">29</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("result:&nbsp;%s\n",&nbsp;buf);<br />
<span style="color: #008080; ">30</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("\t");&nbsp;mpf_out_str(NULL,&nbsp;10,&nbsp;0,&nbsp;r);&nbsp;printf("\n");<br />
<span style="color: #008080; ">31</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(r);<br />
<span style="color: #008080; ">32</span>&nbsp;<br />
<span style="color: #008080; ">33</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">test&nbsp;actual&nbsp;max&nbsp;value:9999<img src="http://www.cppblog.com/Images/dot.gif" alt="" />9(the&nbsp;number&nbsp;of&nbsp;9&nbsp;is&nbsp;38)</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">34</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;max_data[]&nbsp;=&nbsp;{0xd3,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64,0x64};<br />
<span style="color: #008080; ">35</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="color: #800000;">orcl_raw2number</strong>(max_data,&nbsp;<span style="color: #0000FF; ">sizeof</span>(max_data),&nbsp;r);<br />
<span style="color: #008080; ">36</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gmp_snprintf(buf,&nbsp;<span style="color: #0000FF; ">sizeof</span>(buf),&nbsp;"%Ff\n\t%.*Ff(%d&nbsp;digits)",&nbsp;r,&nbsp;n,&nbsp;r,&nbsp;n);<br />
<span style="color: #008080; ">37</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("result:&nbsp;%s\n",&nbsp;buf);<br />
<span style="color: #008080; ">38</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("\t");&nbsp;mpf_out_str(NULL,&nbsp;10,&nbsp;0,&nbsp;r);&nbsp;printf("\n");<br />
<span style="color: #008080; ">39</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(r);<br />
<span style="color: #008080; ">40</span>&nbsp;<br />
<span style="color: #008080; ">41</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">test&nbsp;actual&nbsp;min&nbsp;value:-9999<img src="http://www.cppblog.com/Images/dot.gif" alt="" />9(the&nbsp;number&nbsp;of&nbsp;9&nbsp;is&nbsp;38)</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">42</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;<span style="color: #0000FF; ">char</span>&nbsp;min_data[]&nbsp;=&nbsp;{0x2c,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x66};&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">43</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="color: #800000;">orcl_raw2number</strong>(min_data,&nbsp;<span style="color: #0000FF; ">sizeof</span>(min_data),&nbsp;r);<br />
<span style="color: #008080; ">44</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gmp_snprintf(buf,&nbsp;<span style="color: #0000FF; ">sizeof</span>(buf),&nbsp;"%Ff\n\t%.*Ff(%d&nbsp;digits)",&nbsp;r,&nbsp;n,&nbsp;r,&nbsp;n);<br />
<span style="color: #008080; ">45</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("result:&nbsp;%s\n",&nbsp;buf);<br />
<span style="color: #008080; ">46</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf("\t");&nbsp;mpf_out_str(NULL,&nbsp;10,&nbsp;0,&nbsp;r);&nbsp;printf("\n");<br />
<span style="color: #008080; ">47</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(r);<br />
<span style="color: #008080; ">48</span>&nbsp;<br />
<span style="color: #008080; ">49</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="color: #800000;">clear_mpf_globals</strong>();<br />
<span style="color: #008080; ">50</span>&nbsp;<br />
<span style="color: #008080; ">51</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">test&nbsp;max&nbsp;oracle&nbsp;number&nbsp;value</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">52</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;mpf_init2(r,&nbsp;256);<br />
<span style="color: #008080; ">53</span>&nbsp;<br />
<span style="color: #008080; ">54</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_set_str(r,&nbsp;"1e125",&nbsp;10);<br />
<span style="color: #008080; ">55</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_out_str(NULL,&nbsp;10,&nbsp;0,&nbsp;r);&nbsp;printf("\n");<br />
<span style="color: #008080; ">56</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gmp_printf("%Ff\n",&nbsp;r);<br />
<span style="color: #008080; ">57</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #008080; ">58</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">test&nbsp;min&nbsp;oracle&nbsp;number&nbsp;value</span><span style="color: #008000; "><br />
</span><span style="color: #008080; ">59</span>&nbsp;<span style="color: #008000; "></span>&nbsp;&nbsp;&nbsp;&nbsp;mpf_set_str(r,&nbsp;"-1e125",&nbsp;10);<br />
<span style="color: #008080; ">60</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_out_str(NULL,&nbsp;10,&nbsp;0,&nbsp;r);&nbsp;printf("\n");<br />
<span style="color: #008080; ">61</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gmp_printf("%Ff\n",&nbsp;r);<br />
<span style="color: #008080; ">62</span>&nbsp;<br />
<span style="color: #008080; ">63</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mpf_clear(r);<br />
<span style="color: #008080; ">64</span>&nbsp;<br />
<span style="color: #008080; ">65</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;0;<br />
<span style="color: #008080; ">66</span>&nbsp;}</div>
&nbsp; &nbsp;<strong>输出如下<br />
</strong>&nbsp; &nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/oracle_number_parse_test_output.png" width="1183" height="285" alt="" /><img src ="http://www.cppblog.com/qinqing1984/aggbug/217292.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2020-05-08 12:23 <a href="http://www.cppblog.com/qinqing1984/archive/2020/05/08/217292.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于VSS热备SQL Server的架构及应用</title><link>http://www.cppblog.com/qinqing1984/archive/2020/05/02/217276.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Sat, 02 May 2020 08:31:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2020/05/02/217276.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/217276.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2020/05/02/217276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/217276.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/217276.html</trackback:ping><description><![CDATA[<strong style="font-size: 13pt;">为什么用VSS<br />
</strong>&nbsp;&nbsp;&nbsp;<span style="color: #ff0000;">VSS</span>是Windows系统的卷影像拷贝服务，用于解决如下问题：<br />
<span style="font-size: 8pt;">&nbsp; &nbsp;&nbsp;</span>&nbsp; &nbsp;<span style="font-size: 8pt;">&#9670;&nbsp;</span>许多备份工具涉及打开文件<br />
<span style="font-size: 10.6667px;">&nbsp; &nbsp;&nbsp;</span>&nbsp; &nbsp;<span style="font-size: 10.6667px;">&#9670;&nbsp;</span>但是若一个应用程序已经以独占方式打开文件并进行访问时，备份工具则不能访问该文件<br />
<span style="font-size: 10.6667px;">&nbsp; &nbsp;&nbsp;</span>&nbsp; &nbsp;<span style="font-size: 10.6667px;">&#9670;&nbsp;</span>即使备份工具能够访问已打开的文件，也可能造成备份文件的不一致性<br />
&nbsp;&nbsp;&nbsp;在实际数据灾备中，主流厂商实现SQL Server的热备并不会使用数据库自带的<span style="color: e93366;">backup database</span>/<span style="color: e93366;">backup log</span>命令，因为这种方式在应急容灾(此时源数据库已宕机)挂载数据时要先还原，而还原要连接数据库运行<span style="color: e93366;">restore database</span>/<span style="color: e93366;">restore log</span>命令，这样就需要部署一台机器装上SQL Server专用于还原，不仅增大了成本而且延长了<span style="color: e93300;">RTO</span>；而使用VSS，备份的就是SQL Server的数据文件及日志文件，在应急容灾挂载时可直接打开并用于增删改查，无须还原，免去了机器成本并降低了RTO（只存在数据库挂载时的事务恢复时间）。<br />
<br />
<span style="font-size: 13pt;"><strong>VSS架构</strong></span><br />
&nbsp;&nbsp;&nbsp;VSS包括Requestor、Writer、Provider和VSS核心模块四部分，如下图所示<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/vss_arch.jpg" alt="" /><br />
&nbsp; &nbsp;Requestor在本文中表示热备份应用程序；Writer主要功能是保证数据的一致性，使得那些能够感知影像拷贝的应用程序能够接收到冻结（freeze）和解冻（thaw）通知，以确保其文件的备份拷贝是内在一致的，在本文中即指SQL Server自带的<span style="color: #ff00ff;">SQL Writer</span>；Provider主要功能是创建影像拷贝即打快照，允许将ISV特定的存储方案与影像拷贝服务集成起来，在本文中即<span style="color: e93300;"><strong>volsnap.sys</strong></span>存储过滤型驱动程序，位于文件系统和卷管理器之间；VSS核心模块即图中的卷影像拷贝服务，主要功能是协调各个模块的协作运行，并提供创建及管理卷影像拷贝的API接口。<br />
<br />
<strong style="font-size: 13pt;">VSS原理示例</strong><br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.cppblog.com/images/cppblog_com/qinqing1984/vss_underlaying_operation.jpg" alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;无论何时，当卷影像拷贝驱动程序看到一个针对原始卷的写操作时，它把将要被修改的扇区的内容复制到一个与影像卷相关联的、由页面文件支持的内存区中
&nbsp; &nbsp;&nbsp;<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 10.6667px;">&#9670;&nbsp;</span>对于已修改扇区的影像卷读操作，从该内存区中读取数据<br />
&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: 10.6667px;">&#9670;&nbsp;</span>对于未修改扇区的影像卷读操作，从原始卷中读取<br />
<br />
<strong style="font-size: 13pt;">备份应用程序、Provider和SQL Writer的局限<br />
</strong>&nbsp; &nbsp;<span style="font-size: 10.6667px;">&#9670;&nbsp;</span>只能备份Windows系统支持的本地文件系统上的文件，不支持远程共享或交叉挂载的文件系统<br />
&nbsp; &nbsp;<span style="font-size: 10.6667px;">&#9670;&nbsp;</span>对于系统提供者(Windows系统默认自带的Provider，使用写时拷贝技术)，被拷贝的源卷不必是NTFS卷，但影像卷必须是NTFS卷<br />
&nbsp; &nbsp;<span style="font-size: 10.6667px;">&#9670; SQL Writer</span>支持全量备份及恢复、支持差异备份及恢复和Copy Only备份，但不支持备份连续事务日志、文件和文件组，不支持页恢复<br />
<br />
<strong style="font-size: 13pt;">怎样使用VSS</strong><br />
&nbsp;&nbsp;&nbsp;微软官网提供的VSS SDK 7.2（<a href="https://www.microsoft.com/en-us/download/details.aspx?id=23490" target="_blank">https://www.microsoft.com/en-us/download/details.aspx?id=23490</a>）中自带了<span style="color: S00000;">vshadow</span>和<span style="color: S00000;">betest</span>工具源码，经过笔者修正一些bug(win 10 + vs2010)，并为了备份配置方便将原来的文本换成xml格式，成功地实现了SQL Server的全量热备及恢复、差量热备及恢复<br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt;">vshadow用法</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以管理员身份在ms-dos窗口下执行vshadow.exe&nbsp;/?，可得到所有的帮助<br />
&nbsp; &nbsp; &nbsp; 示例<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;可用vshadow&nbsp;-wm获取当前系统所有写者的元数据，再从中查找SQL&nbsp;Server&nbsp;Writer的写者ID及它下面COM组件的逻辑路径和名称<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;<strong style="font-size: 12pt;">betest用法</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以管理员身份在ms-dos窗口下执行betest.exe&nbsp;/?，可得到所有的帮助<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;示例<br />
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;<strong style="font-size: 11pt;">1. 全量备份SQL&nbsp;Server</strong><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;betest.exe&nbsp;/v&nbsp;<span style="color: #ff00ff;">/b</span>&nbsp;/t&nbsp;<span style="color: #ff00ff;">FULL</span><span style="color: #ff00ff;">&nbsp;</span>/s&nbsp;backupfull.xml&nbsp; /d&nbsp;f:\backupfull&nbsp;/c&nbsp;SQLWriter.xml<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;/v&nbsp;--&nbsp;输出详细信息，可选的<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;/b&nbsp;--&nbsp;备份<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /t&nbsp;--&nbsp;备份类型<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /s&nbsp;--&nbsp;备份/恢复组件XML格式文档，内含写者及其下组件的元数据（非常重要）<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /d&nbsp;--&nbsp;备份目录<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /c&nbsp;--&nbsp;相关写者的配置文件，文件内含写者ID及其下COM组件的逻辑全路径名<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="font-size: 11pt;"><strong>全量恢复SQL&nbsp;Server</strong></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;betest.exe&nbsp;/v&nbsp;<span style="color: #ff00ff;">/r</span>&nbsp;/s&nbsp;backupfull.xml&nbsp; /d&nbsp;f:\backupfull&nbsp; /c&nbsp;SQLWriter.xml<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;/r&nbsp;--&nbsp;恢复<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;其它选项说明同上，下同&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="font-size: 11pt;">2. 差异备份SQL&nbsp;Server</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;betest.exe&nbsp;/v&nbsp;/b&nbsp;/t&nbsp;<span style="color: #ff00ff;">DIFFERENTIAL&nbsp;</span>/s&nbsp;backupdiff.xml&nbsp;<span style="color: #ff00ff;">/pre</span>&nbsp;backupfull.xml&nbsp;/d&nbsp;f:\backupdiff&nbsp;/c&nbsp;SQLWriter.xml<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;/pre&nbsp;--&nbsp;表示前次基准的全量备份生成的组件XML格式文档<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="font-size: 11pt;">差异恢复SQL&nbsp;Server</strong>&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a) betest.exe&nbsp;/v&nbsp;/r&nbsp;<span style="color: #ff00ff;">/AdditionalRestores</span>&nbsp;/s&nbsp;backupfull.xml&nbsp;/d&nbsp;f:\backupfull&nbsp;/c&nbsp;SQLWriter.xml<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/AdditionRestores&nbsp;--&nbsp;用于差异恢复的选项，表示全量后面需要紧跟差异恢复才能完成数据库恢复<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;b) betest.exe&nbsp;/v&nbsp;/r&nbsp;/s&nbsp;backupdiff.xml&nbsp;/d&nbsp;f:\backupdiff&nbsp;/c&nbsp;SQLWriter.xml&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;注意，此时/s跟的是差异备份生成的backupdiff.xml文件，/d跟的是差异备份目录<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<strong style="font-size: 11pt;">3. SQL Writer配置</strong><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<strong style="font-size: 10pt;">xml格式说明</strong><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer节点 <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;id属性&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;---&nbsp; 写者唯一ID<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; server_name属性&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;---&nbsp; SQLServer服务名<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; stop_restore_start属性(可选) ---&nbsp;表示恢复时是否先停止数据库服务再启动，yes表示先停再启，no则反之，这个用于恢复系统数据库master，因为master不支持在线恢复<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;component节点&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;pathname属性 &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;---&nbsp;逻辑路径名<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;file节点<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;src_path节点&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;---&nbsp;SQL Server文件所在路径的匹配模式<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;alternate_path节点&nbsp; &nbsp; &nbsp; &nbsp; --- 恢复时的备选路径，用于合成差异增量<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<strong style="font-size: 10pt;">示例</strong><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;?xml&nbsp;version="1.0"&nbsp;encoding="utf-8"?&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;betest&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&lt;writer&nbsp;id="{a65faa63-5ea8-4ebc-9dbd-a0c4db26912a}"&nbsp; service_name="MSSQLSERVER"&nbsp;stop_restore_start="no"&gt;&nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&lt;component&nbsp;pathname="DESKTOP-JUP320L\master"&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;file&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&lt;src_path&gt;E:\*...&lt;/src_path&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;alternate_path&gt;f:\sqlserver\&lt;/alternate_path&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/file&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/component&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;component&nbsp;pathname="DESKTOP-JUP320L\model"&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&lt;!--file&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&lt;src_path&gt;E:\*...&lt;/src_path&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;alternate_path&gt;f:\sqlserver\&lt;/alternate_path&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/file--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/component&gt;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;component&nbsp;pathname="DESKTOP-JUP320L\test"&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&lt;!--file&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&lt;src_path&gt;E:\*...&lt;/src_path&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&lt;alternate_path&gt;f:\sqlserver\&lt;/alternate_path&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/file--&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/component&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;/writer&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&lt;/betest&gt;
<img src ="http://www.cppblog.com/qinqing1984/aggbug/217276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2020-05-02 16:31 <a href="http://www.cppblog.com/qinqing1984/archive/2020/05/02/217276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>MySQL和Oracle在日志子系统及热备方面的对比心得</title><link>http://www.cppblog.com/qinqing1984/archive/2020/04/21/217247.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Tue, 21 Apr 2020 03:19:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2020/04/21/217247.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/217247.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2020/04/21/217247.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/217247.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/217247.html</trackback:ping><description><![CDATA[阅读《MySQL Innodb无锁化设计的日志系统》（<a href="https://zhuanlan.zhihu.com/p/53037796" target="_blank">https://zhuanlan.zhihu.com/p/53037796</a>）后的心得：<br />
<div><strong style="font-size: 11pt;">与oracle日志子系统异曲同工的差异</strong></div>
<div>&nbsp;1.&nbsp;<span style="color: red;">空洞</span>：对于并发会话copy重做日志造成的空洞，oracle是由lgwr判断并等待持有redo copy闩锁的会话释放后，这时空洞已被填充，可以刷到磁盘了；mysql则是由log writer线程监测到空洞被填充后，再写入一段连续最大lsn的日志到磁盘</div>
<div>&nbsp;2.&nbsp;<span style="color: red;">io方式</span>：oracle的lgwr是direct io；mysql的log writer是写到os的page cache，后由独立的log flusher线程刷盘，比oracle多了一个过程</div>
<div>&nbsp;3.&nbsp;<span style="color: red;">唤醒会话</span>：oracle由lgwr扫描所有等待的会话，只唤醒满足写入条件(事务提交log已刷盘)的会话；mysql则由独立的log flush notifier通过满足条件对应的分片消息队列来唤醒，比oracle多了一个过程</div>
<div>总结：mysql通过原子变量来管理全局log buffer的几个内存位置来实现无锁化，而原子操作在多核上仍不利于线性扩展。oracle的闩锁也存在类似问题，但通过私有redo缓存和多个全局log buffer(相关闩锁量与cpu核数正比)，来提升了扩展性。故整体上oracle更优<br />
<br />
阅读《MySQL/InnoDB数据克隆插件(clone plugin)实现剖析》（<a href="https://zhuanlan.zhihu.com/p/76255304" target="_blank">https://zhuanlan.zhihu.com/p/76255304</a>）后的心得：<br />
<div><strong style="font-size: 11pt;">与oracle老式热备异曲同工的差异</strong></div>
<div>&nbsp;1.&nbsp;<span style="color: red;">page追踪</span>：oracle老式热备实际当每行更新时将整个关联的page记录在redo日志中；mysql热备则是记录变化page的id在单独一个地方，用于page copy阶段从buffer pool读取并发送页数据到备库</div>
<div>&nbsp;2.&nbsp;<span style="color: red;">redo归档</span>：oracle老式热备在拷贝数据文件的全过程，只要数据文件被修改就会有redo归档；mysql热备则仅在page copy阶段启用redo归档，可看做是临时的</div>
<div>&nbsp;3.&nbsp;<span style="color: red;">一致性恢复</span>：oracle老式热备存在数据块分离现象，对此应用被冻结scn及日志序列号后的redo log来恢复；mysql则通过page copy及应用clone lsn后的redo log来恢复</div>
<div>总结：oracle老式热备必须处于归档模式，由于记录整块而非行变化，因此重做日志写放大而增加了cpu和io的开销，由于可能判断并修复分离的块，因此延长了恢复时间；mysql通过page追踪和临时redo归档来减少应用redo的体量而缩短了恢复时间。故mysql热备整体更优，但相对oracle的现代rman备份则并不更优</div>
<div></div>
</div>
<div></div><img src ="http://www.cppblog.com/qinqing1984/aggbug/217247.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2020-04-21 11:19 <a href="http://www.cppblog.com/qinqing1984/archive/2020/04/21/217247.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于数据库的一些学习研究心得</title><link>http://www.cppblog.com/qinqing1984/archive/2019/11/06/216969.html</link><dc:creator>春秋十二月</dc:creator><author>春秋十二月</author><pubDate>Wed, 06 Nov 2019 03:29:00 GMT</pubDate><guid>http://www.cppblog.com/qinqing1984/archive/2019/11/06/216969.html</guid><wfw:comment>http://www.cppblog.com/qinqing1984/comments/216969.html</wfw:comment><comments>http://www.cppblog.com/qinqing1984/archive/2019/11/06/216969.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/qinqing1984/comments/commentRss/216969.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/qinqing1984/services/trackbacks/216969.html</trackback:ping><description><![CDATA[<div>1. <strong style="color: red;">绑定变量</strong>作为一种优化查询处理的方法，在性能上有利有弊，是一把双刃剑。它的优势在于可以共享库缓存中的父游标，从而避免了硬解析及相关的开销；劣势在于因绑定变量扫视增加了查询优化器选择(非常)低效执行计划的风险，即使支持自适应游标共享，也引入了游标感知判断和谓词选择率估算的代价，而且在生成高效的执行计划前至少有一次是无效率的。因此，是否使用绑定变量，需要衡量实际字面值与处理数据量带来的解析执行的收益与损害，当损害大于收益时就不应该使用，反之当处理较少数据硬解析耗时比执行多时，就可以使用了<br /><br />2.&nbsp;<strong>存储快照</strong>一般有三种层次：物理卷、文件系统和应用程序</div><div>&nbsp; &nbsp;&#9670; 物理卷快照基于卷扇区映射表实现，宜采用CoFW法，因为它不必每次写io都去遍历映射表，比RoFW快</div><div>&nbsp; &nbsp;&#9670;&nbsp;文件系统快照基于inode树即元数据复制实现，每当写io时更新快照或源inode的指向，必要时向上回溯至根inode。有的文件系统比如NetApp公司的WAFL则更优，只须复制根inode，因为每次写io时它会变但其下所有的inode不会变</div><div>&nbsp; &nbsp;&#9670; 应用程序快照最典型的就是数据库，原理本质与上述两种一样，基于页改变位图，当page首次(相对于快照创建时刻)改变时拷贝到快照文件(一种稀疏文件)，另外当撤消未提交事务或回滚事务时也会发生拷贝(此时快照慢慢不再稀疏)，这是为了保证快照的可用一致性<br /><br />3. <strong style="color: red;">数据块的加锁</strong>有单机和分布式两种情景，前者是为了同步单实例事务的并发，后者是为了协调分布式事务的同步，并与缓存一致性协议紧密联系。undo,redo,undo/redo三种日志对数据脏块与提交日志记录落盘的顺序要求各不同，因此恢复方式不同。脱服务器备份架构比较好，具有不占用应用服务器资源的优势，而微软的vss可传输卷影拷贝提供了这一支持，足见其技术的先进前瞻性<br /><br /><div>4. Oracle的<strong style="color: red;">实例恢复</strong>完全靠在线重做日志，介质恢复必须靠归档重做日志，以及在线重做日志。然而在线重做日志是有限数量的，那么Oracle是怎样保证宕机经实例恢复后不丢数据？答案是检查点。检查点是数据库中一个很重要的机制，被重做日志切换触发，由DBWn执行刷新脏块，并清除老的无用的在线重做日志，以允许被覆盖<br /><br /><div>5. Linux内核的swap高速缓存和其它的缓存(比如page缓存)不太一样，因为它存在的主要原因不是为了减少磁盘IO提高性能，而是解决换入换出共享匿名页同步即并发swap的问题。那么它是唯一的方法吗？不一定，可以遍历所有的anon_vma链表，查找匿名页对应的页框是否已建立，但该方法没有swap缓存快。当然，在换入操作很多的情景，swap缓存确实能提高系统性能<br /><br />6. Linux内存回收的核心是LRU链表，Oracle的<span style="color: red;"><strong>buffer cache</strong></span>也有个LRU，这两种LRU的共同点是引用计数(标志)和非活跃链表，引用计数会影响一个对象是否移到非活跃链表，非活跃链表用于回收或覆盖这个对象。对于Linux这个对象是页框，移到非活跃链表取决于swap tendency；而Oracle则是数据块buffer及其TCH<br /><br />7. Linux内核中的反向映射让我想起了Oracle中的<strong style="color: red;">反向键索引</strong>，它们的共同点都是为了高性能，前者是为了快速定位引用同一页框的所有页表项，从而方便共享内存的回收；后者是为了减少右侧索引叶块的竞争，从而降低缓冲区忙等待、提高并发量<br /><br />8. <strong style="color: red;">mvcc</strong>与read uncommitted(简称RU)隔离级别的关系究竟如何？这取决于现代数据库的实现。对于Oracle，RU和RC的读实现都基于mvcc实现，换句话说Oracle其实没有脏读；对于MySQL innodb引擎，mvcc不适用于RU而只适用于RC/RR级别，因为RC/RR必须读取修改已提交的数据，但基准点不同，前者查询开始时、后者事务开始时，而RU则可读取未提交的数据，当然用mvcc模拟实现RU应该也可以，只需要读取当前新版本而非旧版本<br /><br />9. 借助内核page cache的数据库或者存储引擎，一定程度上讲，是粗暴懒惰的表现，这会导致系统负载比较重的情况下，io性能很差。所以为高性能，必须得处理好direct io，设计<strong style="color: red;">self cache</strong>，这样一来，就避免了浪费在原先内核页缓存的页框，避免处理内核页缓存和预读的多余指令而提高了系统调用read和write的效率，同时减少了一次数据拷贝<br /><br />10. <strong style="color: red;">SQL半连接</strong>的本质是在内连接的基础上对内表去重，即使内表有符合多个连接条件的元组，也只匹配一条，从而减少了连接返回的结果集。一般地，简单的in、exists和any子句，都采用半连接实现，但若内表本身保证了唯一性，则半连接可消除转为内连接实现，或者内表数据量很小且外表存在索引，那么也会消除半连接，生成由内表驱动外表，外表走索引的执行计划。由此一例看出，SQL优化器偏爱内连接，因为内连接带来了驱动表选择和谓词下推的灵活，便于产生更优的执行计划<br /><br />11. 从Oracle数据库内核角度讲，<strong style="color: red;">游标</strong>代表SQL语句的句柄，包含了依赖对象及执行计划等信息，它相当于linux的文件描述符和windows的句柄。打开或缓存的游标是指对应SQL语句所占的内存(父游标句柄、父堆0和子游标句柄的chunk)被加上kgl lock和pin锁，意味着第三次后解析同样的SQL不必再从library cache hash chain中加锁查找而直接从PGA的子堆6地址中获取并调用执行计划，如此优化提高了并发度加快了查询，这正是软软解析；软软解析前必须软解析2次，目的是将library cache的执行计划在PGA中做一份链接，软解析前必须硬解析，目的是将执行计划放在library cache中。然而，如果共享池空闲内存不足，或者依赖对象发生DDL操作导致执行计划失效，那么执行计划所占chunk可以被覆盖释放，这样一来，软(软)解析时就需要重新生成执行计划了<br /><br />12. <strong style="color: red;">Oracle的内存管理</strong>粗略地类似于Linux内核，所不同的是内存分配单元，前者叫granule通常大小4M~16M，后者叫page通常4K；数据块缓冲的分配类似伙伴算法，共享池(主要用于sql缓存)的chunk分配类似slab算法，共享池中的保留池类似基于slab的内存池<br /><br />13. Oracle数据库究竟是怎样构建表<strong style="color: red;">数据块的读一致性</strong>版本？这是个比较复杂、细致和有趣的问题，核心流程如下</div><div>&nbsp; &nbsp;&#9670;&nbsp;克隆数据块，若不存在则先从磁盘读，下面几步以克隆块为目标</div><div>&nbsp; &nbsp;&#9670;&nbsp;根据ITL中的flag及lck，对所有已提交的事务做清除操作，即延迟块清除。延迟块清除为了获取足够精确的提交SCN填充到ITL，分2种情况，若事务表槽没被覆盖，则直接用其提交SCN；否则先从事务控制区获取SCN，并判断对于上界提交是否足够精确，若不够则需要回滚事务表一直找到合适的SCN或报错ORA-01555</div><div>&nbsp; &nbsp;&#9670;&nbsp;根据ITL中的uba，反向更改所有未提交的事务，也就是应用事务的undo记录</div><div>&nbsp; &nbsp;&#9670;&nbsp;根据ITL中的SCN，不断反向更改大于目标SCN的已提交事务，直至遇见合适的已提交事务。这里也是应用undo记录，但不同的是，除了应用行数据，还会从事务的第一个undo记录找到先前即前一个已提交事务的ITL项拷贝回当前块的对应ITL项<br /><br />14. Oracle的多版本控制机制，为dml不仅提供了一致且正确的结果，还提高了并发性，可谓鱼和熊掌兼得。那么它的缺点是什么？可能会导致热表的IO增高，因为读一致性需要不断回滚多个事务对数据块的修改，直到查询开始时的数据。事务隔离级别read committed与read uncommitted的相同是不会脏读，区别是前者会不可重复读或幻读<br /><br />15. Sql*plus的<strong style="color: red;">ARRAYSIZE</strong>对查询数据性能有重要的影响，这个值过大过小都不好，而是要接近一个数据块所拥有的行数，如此仅一次逻辑IO就拿到了一批行。那么设置合适的ARRAYSIZE就一定能提高性能吗？不一定，还要看所查询的表使用了什么索引列及表数据在磁盘上的物理布局，若数据分散即聚簇因子低，则优化器会选用全表而非索引区间扫描，去执行这个查询<br /><br />16. <strong style="color: red;">IOT表</strong>如果为非主键列再建索引，那么就成二级索引。这时候查询数据，需要两次扫描，一是扫描二级索引得到IOT中的位置，二是扫描IOT本身匹配那个位置，之所以这样是因为行记录在IOT中的位置会变。而堆组织表，仅需一次扫描索引结构，得到rowid，再直接读磁盘获取行记录。因此IOT上再建二级索引，并非明智的选择<br /><br />17. 相容性矩阵是封锁调度的核心结构; 任意一个无环优先图的封锁调度都是冲突可串行化的; 基于树协议的无环优先图的封锁调度，其整个事务集合的任意一个拓扑顺序都是等价可串行化的<br /><br />18. 总结解决数据库<strong style="color: red;">丢失更新</strong>问题的方案</div><div>&nbsp; &nbsp; &nbsp;&#9670;&nbsp;对于表不会被悲观锁锁定的情景：使用基于select+update的乐观锁方法，查询保存前映像，以便定位更新。前映像列可为全列，或新增一个时间戳列作为版本列</div><div>&nbsp; &nbsp; &nbsp;&#9670;&nbsp;对于表可能会被悲观锁锁定的情景：使用select&#8230;for update nowait+update的悲观锁方法，可以以全列的hash(虚拟列)来定位更新<br /><br />19. 如果能够在备库上打开闪回，那么就可以做到既让生产系统没有承担闪回的开销，又能快速地为错误或故障恢复到以前某个时刻。一举两得比较完美，重做日志的创新使用真是太棒了<br /><br />20. Oracle的<strong style="color: red;">索引聚簇表</strong>是个创新，它能将多个不同表的行按照索引列存储在同一块中，属于物理上的join，这样一来既可减少data buffer缓存的块数而提高效率，又可提高多个相关表连接查询的性能，比如通过外键约束的父子表。最典型的应用就是数据字典，数据字典对于查询优化的成本估算很重要，由此可见oracle的设计之明智，mysql的innodb只有索引组织表，sql server有堆表和索引组织表，但它们都没有索引聚簇表<br /><br />21. 分布式事务处理是工程难题。Oracle的<span style="color: red;"><strong>serializable串行隔离级别</strong></span>以乐观锁实现，所以并发度与非串行相当，需要注意的是：串行并不是说一个事务提交了才能处理下一个，而是多个事务间没有冲突表现地像只有一个事务在运行，否则Oracle的serializable级别就不存在抛出ORA-08177错误了<br /><br />22. 理清<span style="color: red;"><strong>read uncommitted</strong></span><span style="color: #000000;">事务隔离级别</span>的锁策略：读不加共享锁，写加排它锁直至提交，这里的锁是指lock；块的缓冲区并发操作必须加锁，这里的锁是指latch，若不加，那脏读读到的数据可能是错的。脏读隔离级别允许读修改但未提交的行记录，这意味着读不能被写阻塞，也不能阻塞写，所以不会申请共享锁（显式锁定读除外）<br /><br />23. 与MySQL不同，Oracle的<span style="color: red;"><strong>行锁</strong></span>无需索引列的限制，是真正的行锁，其实现为数据块的属性而非传统的锁管理器，但是它需要在事务commit或rollback时才释放，如果存在慢sql，那么导致的阻塞会比较严重<br /><br />24. 隔离是实现安全的一种办法，其结果常被称作&#8220;沙箱&#8221;。从这个意义上讲Oracle很明智，因为它的事务没有也不需要read uncommitted隔离级别，Oracle最低且默认的隔离级别是<span style="color: red;"><strong>read committed</strong></span>，因为它有基于undo的多版本控制，天生非阻塞读，根本不会脏读。我想不出read uncommitted有什么好处，除了非阻塞读及可能的高并发，要谨慎脏读是危险不安全的<br /><br />25. windows内存映射和linux内存映射的实现机制不太一样，前者使用了内存区section的专用数据结构而不像后者重用了页缓存，内存区的映射完全由内存管理器负责包括物理页分配及脏页面写入器，与缓存管理器无关；缓存管理器基于内存管理器维护了文件块数据的视图，并提供了自己的延迟写入器。这两种写入器即回刷，独立并行地工作</div></div></div><img src ="http://www.cppblog.com/qinqing1984/aggbug/216969.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/qinqing1984/" target="_blank">春秋十二月</a> 2019-11-06 11:29 <a href="http://www.cppblog.com/qinqing1984/archive/2019/11/06/216969.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>