<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>微软亚太区数据库技术支持组 官方博客</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/apgcdsd/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/apgcdsd/feed.xml</link>
    <description />
    <lastBuildDate>Tue, 21 Jul 2015 08:43:12 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>SQL Server性能问题案例解析 （3）</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/sql-server-3-2</link>
      <pubDate>Wed, 01 Jul 2015 20:03:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/07/01/sql-server-3-2/</guid>
      <description><![CDATA[今天的博客是SQL Server...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: medium;">今天的博客是SQL Server 性能问题解析系列的最后一个案例。这个案例背景是用户反映以下查询语句执行时间过长，执行时间为10秒以上（已经排除了blocking原因），希望将执行时间压缩到2秒以内。</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">declare @Company as varchar</span><span style="font-size: medium;">(10)</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">set @Company = 'a'</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">declare @SystemVersion as </span><span style="font-size: medium;">varchar(30)</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">set @SystemVersion = 'Total </span><span style="font-size: medium;">Ticketing Solution v2.1.3'</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">declare @LocationID_PSS as </span><span style="font-size: medium;">varchar (10)</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">declare @UserCode_PSS as </span><span style="font-size: medium;">varchar (10)</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">declare @ProductId_PSS as </span><span style="font-size: medium;">varchar (10)</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">declare @TrxDateFr as datetime</span></p>
<p><span style="color: #0000ff; font-size: medium;">declare @TrxDateTo as datetime</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @LocationID_PSS = null</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @UserCode_PSS = null</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @ProductId_PSS = null</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @TrxDateFr = '2006-5-17'</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @TrxDateTo = '2006-5-18'</span></p>
<p><span style="color: #0000ff; font-size: medium;">SELECT</span></p>
<p><span style="color: #0000ff; font-size: medium;">@Company as company,</span></p>
<p><span style="color: #0000ff; font-size: medium;">@SystemVersion as version,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">@TrxDateFr AS </span><span style="font-size: medium;">TrxDateFrom,&nbsp; @TrxDateTo&nbsp; AS TrxDateTo,</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">l.LocationID,</span></p>
<p><span style="color: #0000ff; font-size: medium;">l.LocationDesc,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TH.ClientPCName,</span></p>
<p><span style="color: #0000ff; font-size: medium;">ProductDesc =&nbsp;</span><span style="color: #0000ff; font-size: medium;">(P.ProductDesc1 + ' ' + P.ProductDesc2),</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.PkgHDDesc ,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.PassTypecode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.SellingPrice,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.TktAmt,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.DiscountDesc,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TPD.PayTypeCode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TPD.PaymodeCode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TP.Status,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">COUNT(TD.TicketNo) AS </span><span style="font-size: medium;">TotalTktQty,</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">TotalAmt = sum (TD.TktAmt)</span></p>
<p><span style="color: #0000ff; font-size: medium;">FROM</span></p>
<p><span style="color: #0000ff; font-size: medium;">TransactionHd TH&nbsp; ,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TransactionDetail </span><span style="font-size: medium;">TD&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TransactionPaymentDetail </span><span style="font-size: medium;">TPD&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">Product P&nbsp;&nbsp; , </span><span style="font-size: medium;">Location l&nbsp;&nbsp;</span></span><span style="color: #0000ff;"><span style="font-size: medium;">,TransactionPayment TP&nbsp;&nbsp; ,</span><span style="font-size: medium;">TimeSlot TS&nbsp;</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">WHERE</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TH.TrxHdID = TD.TrxHdID AND </span><span style="font-size: medium;">TD.TrxDetailID = </span><span style="font-size: medium;">TP.TrxDetailID AND</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TP.TrxPaymentDetailID=TPD.TrxPaymentDetailID </span><span style="font-size: medium;">AND</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">P.ProductID </span><span style="font-size: medium;">=TS.ProductID&nbsp;&nbsp; AND</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TD.TimeSlotID=TS.TimeSlotID </span><span style="font-size: medium;">AND</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">L.LocationID = Th.LocationID </span><span style="font-size: medium;">AND&nbsp; </span><span style="font-size: medium;">((L.LocationID = </span><span style="font-size: medium;">@LocationID_PSS)OR (@LocationID_PSS IS NULL)) </span></span></p>
<p><span style="color: #0000ff; font-size: medium;">AND </span><span style="color: #0000ff;"><span style="font-size: medium;">((TPD.LastUpdateBy </span><span style="font-size: medium;"><a href="mailto:=@UserCode_PSS)OR"><span style="color: #0000ff;">=@UserCode_PSS)OR</span></a> (@UserCode_PSS IS NULL)) AND</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TP.Status IN ('SOLD' , </span><span style="font-size: medium;">'REFUND', 'VOID') AND </span><span style="font-size: medium;">((P.ProductID = @ProductId_PSS</span></span><span style="color: #0000ff;"><span style="font-size: medium;">) <br />OR (@ProductID_PSS IS NULL)) AND </span><span style="font-size: medium;">( ( ((TH.LastUpdateBy </span><span style="font-size: medium;">=@UserCode_PSS)OR (@UserCode_PSS IS NULL))&nbsp; AND (TH.LastUpdateDate BETWEEN</span></span><br /><span style="color: #0000ff; font-size: medium;">@TrxDateFr AND&nbsp; dateadd( d, 0 ,@TrxDateTo)))&nbsp;</span></p>
<p><span style="color: #0000ff; font-size: medium;">OR</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">(((<a href="mailto:TP.CancelBy=@UserCode_PSS)OR"><span style="color: #0000ff;">TP.CancelBy</span></a></span><span style="font-size: medium;"><a><span style="color: #0000ff;">=@UserCode_PSS)OR</span></a> (@UserCode_PSS IS NULL)) AND (TP.CancelDateTime BETWEEN</span></span><br /><span style="color: #0000ff; font-size: medium;">@TrxDateFr AND&nbsp; dateadd( d, 0 ,@TrxDateTo)) ) )</span></p>
<p><span style="color: #0000ff; font-size: medium;">GROUP BY L.LocationID,</span></p>
<p><span style="color: #0000ff; font-size: medium;">L.LocationDesc,Th.ClientPCName,TH.Lastupdateby,</span><span style="color: #0000ff; font-size: medium;">TP.CancelBy ,&nbsp; TD.IsVoucher, TD.TktTypeCode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">P.ProductDesc1,P.ProductDesc2,TD.PkgHDDesc,</span><span style="color: #0000ff; font-size: medium;">TD.PassTypeCode,TD.SellingPrice , TD.TktAmt, TD.IsGroup, TD.PaxQty,</span></p>
<p><span style="color: #0000ff; font-size: medium;">DiscountDesc, DiscountPerCent,</span><span style="color: #0000ff; font-size: medium;">DiscountValue ,TPD.PayTypeCode, TPD.PaymodeCode, TP.Status</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">首先执行set statistics profile on, set statistics io on和set </span><span style="font-size: medium;">statistics time on 来获取语句的执行计划和相关执行信息，我们会看到统计信息基本准确，排除了统计信息过时的问题。</span><br /><span style="font-size: medium;"><br />接下来我们来看下IO和CPU的相关信息， 我们可以看到'<strong>TransactionDetail'</strong>所消耗的逻辑读最多，达到了32895， 第二名是<strong>TransactionPayment</strong>，达到了4721. 而<strong>TransactionPaymentDetail</strong>的读取次数最多，达到了4616次。</span></p>
<p><span style="color: #800000;"><span style="font-size: medium;"><span style="background-color: #ffff00;"><strong>Table 'TransactionPaymentDetail'. Scan count 4616, logical reads 14787</strong></span>, physical reads 0, read-ahead reads 0, lob </span><span style="font-size: medium;">logical reads 0, lob physical reads 0, lob read-ahead reads 0.</span></span></p>
<p><span style="color: #800000; font-size: medium;">Table</span><br /><span style="color: #800000;"><span style="font-size: medium;">'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads </span><span style="font-size: medium;">0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.</span></span></p>
<p><span style="color: #800000; font-size: medium;">Table</span><br /><span style="color: #800000;"><span style="font-size: medium;">'TransactionHd'. Scan count 1, logical reads 4678, physical reads 0, read-ahead </span><span style="font-size: medium;">reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.</span></span></p>
<p><span style="color: #800000; font-size: medium;">Table</span><br /><span style="color: #800000;"><span style="font-size: medium;">'TransactionPayment'. Scan count 1, logical reads 4721, physical reads 0, </span><span style="font-size: medium;">read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead </span><span style="font-size: medium;">reads 0.</span></span></p>
<p><span style="color: #800000;"><span style="font-size: medium;"><span style="background-color: #ffff00;"><strong>Table 'TransactionDetail'. Scan count 1, logical reads 32895</strong></span>, physical reads 0, read-ahead reads 0, lob </span><span style="font-size: medium;">logical reads 0, lob physical reads 0, lob read-ahead reads 0.</span></span></p>
<p><span style="color: #800000;"><span style="font-size: medium;">Table </span><span style="font-size: medium;">'TimeSlot'. Scan count 1, logical reads 666, physical reads 0, read-ahead reads </span><span style="font-size: medium;">0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.</span></span></p>
<p><span style="color: #800000;"><span style="font-size: medium;">Table </span><span style="font-size: medium;">'Product'. Scan count 1, logical reads 4, physical reads 0, read-ahead reads 0, </span><span style="font-size: medium;">lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.</span></span></p>
<p><span style="color: #800000;"><span style="font-size: medium;">Table </span><span style="font-size: medium;">'Location'. Scan count 1, logical reads 3, physical reads 0, read-ahead reads </span><span style="font-size: medium;">0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.<br /></span></span></p>
<p><span style="font-size: medium;"><strong>TransactionPaymentDetail</strong>在index seek之后和<strong>TransactionDetail</strong>进行了nested </span><span style="font-size: medium;">loop, 对于sql server来说，nested如果大量执行，是非常消耗cpu的，也会增加执行时间。<br /><br /></span><span style="font-size: medium;">实际的执行计划显示，<strong>TransactionDetail</strong>和<strong>TransactoinPayment</strong>两张表占用了54%的性能消耗。</span></p>
<p><br />&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/36425.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/36425.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/36425.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x10000/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/36425.1.png" alt="" width="602" height="260" border="0" /></a><br />&nbsp;<br />&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;</p>
<p><span style="font-size: medium;">两张表都采用了cluster index scan而不是seek。 这是两张表关联的方式 - TD.TrxDetailID = TP.TrxDetailID。检查发现连接的字段的类型相同，这一点上没有问题。<br /><br /></span><span style="font-size: medium;">将鼠标悬浮在TransactoinPayment上，发现上面的Predicate有很多or的操作，这很可能导致了sql生成过于复杂的执行计划，增长了执行时间。</span></p>
<p><span style="font-size: medium;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/5228.2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/5228.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/5228.2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/5228.2.png" alt="" width="302" height="406" border="0" /></a></span></p>
<p><span style="font-size: medium;">在语句的尾部，发现了or的语句:</span></p>
<p><span style="color: #0000ff; font-size: medium;">OR</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">(((TP.CancelBy </span><span style="font-size: medium;"><a href="mailto:=@UserCode_PSS)OR"><span style="color: #0000ff;">=@UserCode_PSS)OR</span></a> (@UserCode_PSS IS NULL)) AND (TP.CancelDateTime BETWEEN</span></span><br /><span style="color: #0000ff; font-size: medium;">@TrxDateFr AND&nbsp; dateadd( d, 0 ,@TrxDateTo)) ) )</span>&nbsp;</p>
<p><span style="font-size: medium;">在t-sql语句中，or和union是可以互换的。于是进行如下改写，即将最后的or的两个条件拆成两个select语句然后进行union操作， 之后语句能在2秒内就完成了。 需要注意的是，对于or或union，并没有确定的孰优孰劣，使用时要进行测试才能确定。</span><br /><br /></p>
<p><span style="color: #0000ff; font-size: medium;">declare @Company as varchar (10)</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @Company = 'a'</span></p>
<p><span style="color: #0000ff; font-size: medium;">declare @SystemVersion as varchar(30)</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @SystemVersion = 'Total Ticketing Solution v2.1.3'</span></p>
<p><span style="color: #0000ff; font-size: medium;">declare @LocationID_PSS as varchar (10)</span></p>
<p><span style="color: #0000ff; font-size: medium;">declare @UserCode_PSS as varchar (10)</span></p>
<p><span style="color: #0000ff; font-size: medium;">declare @ProductId_PSS as varchar (10)</span></p>
<p><span style="color: #0000ff; font-size: medium;">declare @TrxDateFr as datetime</span></p>
<p><span style="color: #0000ff; font-size: medium;">declare @TrxDateTo as datetime</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @LocationID_PSS = null</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @UserCode_PSS = null</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @ProductId_PSS = null</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @TrxDateFr = '2006-5-17'</span></p>
<p><span style="color: #0000ff; font-size: medium;">set @TrxDateTo = '2006-5-18'</span></p>
<p><span style="color: #0000ff; font-size: medium;">SELECT</span></p>
<p><span style="color: #0000ff; font-size: medium;">@Company as company,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">@SystemVersion </span><span style="font-size: medium;">as version,</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">@TrxDateFr AS TrxDateFrom,&nbsp;</span><br /><span style="color: #0000ff; font-size: medium;">@TrxDateTo&nbsp; AS TrxDateTo,</span></p>
<p><span style="color: #0000ff; font-size: medium;">l.LocationID,</span></p>
<p><span style="color: #0000ff; font-size: medium;">l.LocationDesc,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TH.ClientPCName,</span></p>
<p><span style="color: #0000ff; font-size: medium;">ProductDesc =&nbsp; (P.ProductDesc1 + ' ' + P.ProductDesc2),</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.PkgHDDesc ,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.PassTypecode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.SellingPrice,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.TktAmt,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.DiscountDesc,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TPD.PayTypeCode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TPD.PaymodeCode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TP.Status, </span><span style="color: #0000ff; font-size: medium;">COUNT(TD.TicketNo) AS TotalTktQty,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TotalAmt = sum (TD.TktAmt)</span></p>
<p><span style="color: #0000ff; font-size: medium;">FROM</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TransactionHd </span><span style="font-size: medium;">TH&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TransactionDetail </span><span style="font-size: medium;">TD&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TransactionPaymentDetail </span><span style="font-size: medium;">TPD&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">Product </span><span style="font-size: medium;">P&nbsp;&nbsp; , </span></span><span style="color: #0000ff;"><span style="font-size: medium;">Location </span><span style="font-size: medium;">l&nbsp;&nbsp; ,TransactionPayment </span><span style="font-size: medium;">TP&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TimeSlot </span><span style="font-size: medium;">TS&nbsp;</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">WHERE</span></p>
<p><span style="color: #0000ff; font-size: medium;">TH.TrxHdID = TD.TrxHdID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.TrxDetailID = TP.TrxDetailID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">TP.TrxPaymentDetailID=TPD.TrxPaymentDetailID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">P.ProductID =TS.ProductID&nbsp;&nbsp; AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.TimeSlotID=TS.TimeSlotID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">L.LocationID = Th.LocationID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">((L.LocationID = @LocationID_PSS)OR (@LocationID_PSS IS NULL)) AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">((TPD.LastUpdateBy =@UserCode_PSS)OR (@UserCode_PSS IS NULL)) AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">TP.Status IN ('SOLD' , 'REFUND', 'VOID') AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">((P.ProductID = @ProductId_PSS ) OR (@ProductID_PSS IS NULL)) AND</span></p>
<p><span style="color: #0000ff; background-color: #ffff00;"><strong><span style="font-size: medium;">(</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: medium;">( ((TH.LastUpdateBy =@UserCode_PSS)OR (@UserCode_PSS IS NULL))&nbsp; AND (TH.LastUpdateDate BETWEEN @TrxDateFr AND&nbsp;</span></strong></span><br /><span style="color: #0000ff; background-color: #ffff00;"><strong><span style="font-size: medium;">dateadd( d, 0 ,@TrxDateTo)))&nbsp;</span><span style="font-size: medium;">)</span></strong></span></p>
<p><span style="color: #0000ff; font-size: medium;">GROUP BY L.LocationID,</span></p>
<p><span style="color: #0000ff; font-size: medium;">L.LocationDesc,Th.ClientPCName,TH.Lastupdateby, TP.CancelBy ,&nbsp; TD.IsVoucher, TD.TktTypeCode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">P.ProductDesc1,P.ProductDesc2,TD.PkgHDDesc, TD.PassTypeCode,TD.SellingPrice , TD.TktAmt, TD.IsGroup, TD.PaxQty,</span></p>
<p><span style="color: #0000ff; font-size: medium;">DiscountDesc, DiscountPerCent, </span><span style="color: #0000ff; font-size: medium;">DiscountValue ,TPD.PayTypeCode, TPD.PaymodeCode, TP.Status</span></p>
<p><span style="color: #0000ff; background-color: #ffff00;"><strong><span style="font-size: medium;">Union</span></strong></span></p>
<p><span style="color: #0000ff; font-size: medium;">SELECT</span></p>
<p><span style="color: #0000ff; font-size: medium;">@Company as company,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">@SystemVersion </span><span style="font-size: medium;">as version,</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">@TrxDateFr AS TrxDateFrom,&nbsp;</span><br /><span style="color: #0000ff; font-size: medium;">@TrxDateTo&nbsp; AS TrxDateTo,</span></p>
<p><span style="color: #0000ff; font-size: medium;">l.LocationID,</span></p>
<p><span style="color: #0000ff; font-size: medium;">l.LocationDesc,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TH.ClientPCName,</span></p>
<p><span style="color: #0000ff; font-size: medium;">ProductDesc =&nbsp; (P.ProductDesc1 + ' ' + P.ProductDesc2),</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.PkgHDDesc ,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.PassTypecode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.SellingPrice,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.TktAmt,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.DiscountDesc,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TPD.PayTypeCode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">TPD.PaymodeCode,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TP.Status, </span><span style="font-size: medium;">COUNT(TD.TicketNo) AS TotalTktQty,</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">TotalAmt = sum (TD.TktAmt)</span></p>
<p><span style="color: #0000ff; font-size: medium;">FROM</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TransactionHd </span><span style="font-size: medium;">TH&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TransactionDetail </span><span style="font-size: medium;">TD&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TransactionPaymentDetail </span><span style="font-size: medium;">TPD&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">Product </span><span style="font-size: medium;">P&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">Location </span><span style="font-size: medium;">l&nbsp;&nbsp; ,TransactionPayment </span><span style="font-size: medium;">TP&nbsp;&nbsp; ,</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TimeSlot </span><span style="font-size: medium;">TS&nbsp;</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">WHERE</span></p>
<p><span style="color: #0000ff; font-size: medium;">TH.TrxHdID = TD.TrxHdID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.TrxDetailID = TP.TrxDetailID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">TP.TrxPaymentDetailID=TPD.TrxPaymentDetailID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">P.ProductID =TS.ProductID&nbsp;&nbsp; AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">TD.TimeSlotID=TS.TimeSlotID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">L.LocationID = Th.LocationID AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">((L.LocationID = @LocationID_PSS)OR (@LocationID_PSS IS NULL)) AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">((TPD.LastUpdateBy =@UserCode_PSS)OR (@UserCode_PSS IS NULL)) AND</span></p>
<p><span style="color: #0000ff; font-size: medium;">TP.Status IN ('SOLD' , 'REFUND', 'VOID') AND</span></p>
<p><span style="color: #0000ff; background-color: #ffff00;"><strong><span style="font-size: medium;">((P.ProductID = @ProductId_PSS ) OR (@ProductID_PSS IS NULL)) AND</span></strong></span></p>
<p><span style="color: #0000ff; background-color: #ffff00;"><strong><span style="font-size: medium;">(</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: medium;">(((TP.CancelBy =@UserCode_PSS)OR (@UserCode_PSS IS NULL)) AND (TP.CancelDateTime BETWEEN @TrxDateFr AND&nbsp;</span></strong></span><br /><span style="color: #0000ff; background-color: #ffff00;"><strong><span style="font-size: medium;">dateadd( d, 0 ,@TrxDateTo)) )</span><span style="font-size: medium;">)</span></strong></span></p>
<p><span style="color: #0000ff; font-size: medium;">GROUP BY L.LocationID,</span></p>
<p><span style="color: #0000ff; font-size: medium;">L.LocationDesc,Th.ClientPCName,TH.Lastupdateby, TP.CancelBy ,&nbsp; TD.IsVoucher, TD.TktTypeCode,</span></p>
<p><span style="color: #0000ff; font-size: medium;">P.ProductDesc1,P.ProductDesc2,TD.PkgHDDesc, TD.PassTypeCode,TD.SellingPrice , TD.TktAmt, TD.IsGroup, TD.PaxQty,</span></p>
<p><span style="color: #0000ff; font-size: medium;">DiscountDesc, DiscountPerCent,</span><br /><span style="color: #0000ff; font-size: medium;">DiscountValue ,TPD.PayTypeCode, TPD.PaymodeCode, TP.Status</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">另外这个语句也可以用另一种思路去调优，那就是仔细分析下语句的逻辑，看是否可以简化，我们可以发现这个语句中以下这部分代码非常繁琐。</span></p>
<p>&nbsp;</p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">((L.LocationID = </span><span style="font-size: medium;">@LocationID_PSS)OR (@LocationID_PSS IS NULL)) AND</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">((TPD.LastUpdateBy </span><span style="font-size: medium;"><a href="mailto:=@UserCode_PSS)OR"><span style="color: #0000ff;">=@UserCode_PSS)OR</span></a> (@UserCode_PSS IS NULL)) AND</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">TP.Status IN ('SOLD' ,</span><span style="font-size: medium;">'REFUND', 'VOID') AND </span></span><span style="color: #0000ff;"><span style="font-size: medium;">((P.ProductID = @ProductId_PSS</span><span style="font-size: medium;">) OR (@ProductID_PSS IS NULL)) AND</span></span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">进一步查看会发现<strong>@LocationID_PSS，@UserCode_PSS</strong>和<strong>@ProductID_PSS</strong>这些参数的值就是NULL，然而当他们是NULL值的时候，以上条件其实是多余的，我们完全可以移除它们，经过测试，移除后执行计划简化了很多，执行速度更是大大提高。因此我们可以在这个语句前加一个IF&hellip;ELSE的条件，通过IF来判断这些参数是否为NULL值，如果是，则执行移除这些条件的语句，如果不是，则再运行上面调优后使用UNION的语句。这样使得这个语句的运行速度达到了最优化。<br /><br /></span><span style="font-size: medium;">这就是今天的分享，更多SQL Server技术文章请持续关注本博客的更新。</span></p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>SQL Server性能问题案例解析 （2）</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/sql-server-2-2</link>
      <pubDate>Tue, 30 Jun 2015 22:31:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/06/30/sql-server-2-2/</guid>
      <description><![CDATA[语句执行时间长是SQL Server...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: medium;">语句执行时间长是SQL Server 性能问题的一种典型表现形式。当运行一条语句所需要的CPU时间较长或者所需的内存资源较多时，我们往往需要对目标语句本身进行调优。通常情况下，我们可以通过更新统计信息，修改索引，使用语句执行计划的强制选择(使用Hint), 以及对于语句本身的修改来使得语句占用更少的CPU时间或者内存。<br /><br /></span><span style="font-size: medium;">在对问题语句调优之前，我们需要得到这条语句的执行计划。除了通过SQL Server </span><span style="font-size: medium;">Management Studio上的 "Include Actual Execution </span><span style="font-size: medium;">Plan"这个图标外，我们可以通过SQL Server Profiler中Performance - Showplan Statistics Profile这个事件的捕捉来获得语句的执行计划。<br /><br /></span><span style="font-size: medium;">另外在问题语句执行时通过下面的方式可以收集到较为直观和详细的执行计划和相关统计信息。</span></p>
<p>&nbsp;</p>
<p><span style="color: #0000ff; font-size: medium; background-color: #ffffff;">SET STATISTICS IO ON;</span></p>
<p><span style="color: #0000ff; font-size: medium; background-color: #ffffff;">SET STATISTICS TIME ON;</span></p>
<p><span style="color: #0000ff; font-size: medium; background-color: #ffffff;">SET STATISTICS PROFILE ON;</span></p>
<p><span style="color: #0000ff; font-size: medium; background-color: #ffffff;">GO</span></p>
<p><span style="color: #339966; font-size: medium;">--问题语句执行</span></p>
<p><span style="color: #0000ff; font-size: medium;">GO</span></p>
<p><span style="color: #0000ff; font-size: medium;">SET STATISTICS IO OFF;</span></p>
<p><span style="color: #0000ff; font-size: medium;">SET STATISTICS TIME OFF;</span></p>
<p><span style="color: #0000ff; font-size: medium;">SET STATISTICS PROFILE OFF;</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">下面开始我们的案例分析。 在这个案例中，客户最初碰到的问题是SQL Server 进程CPU使用率很高。通过我们的分析定位发现了占用CPU时间最多的语句。在这篇博文中，我们会着重分析这条问题语句占用较高CPU资源的原因。<br /><br /></span><span style="font-size: medium;">问题语句本身是对一个用户定义视图运行select * 语句，相应的constraint也较为简单。但是这个视图的定义较为复杂，对应的定义我们简化如下：</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">CREATE VIEW [dbo].[demoView]</span></p>
<p><span style="font-size: medium;">AS</span><br /><span style="font-size: medium;">WITH&nbsp;&nbsp;&nbsp; DemoInfo</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AS (Complex_Select_Query)</span>&nbsp;&nbsp;<br /><span style="font-size: medium;">SELECT&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;</span></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="font-size: medium;">DISTINCT</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias31 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias32 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias33 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias34 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias35 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias36 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias325,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;ColumnAlias326 = CASE WHEN EXISTS ( SELECT TOP </span><span style="font-size: medium;">1</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">&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; FROM&nbsp;&nbsp;&nbsp; DemoInfo b</span></span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">&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; WHERE&nbsp;&nbsp; b.ColumnAlias328 = a.ColumnAlias328</span><span style="font-size: medium;">&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND&nbsp; </span><span style="font-size: medium;">a.ColumnAlias33 &gt; b.ColumnAlias33 )</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;THEN NULL</span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE a.ColumnAlias326</span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END ,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias327 = CASE WHEN EXISTS (</span><span style="font-size: medium;">SELECT TOP 1</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">&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; FROM&nbsp;&nbsp;&nbsp; DemoInfo b</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">&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;WHERE&nbsp;&nbsp; b.ColumnAlias328 = a.ColumnAlias328</span><span style="font-size: medium;">&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND </span><span style="font-size: medium;">a.ColumnAlias33 &gt; b.ColumnAlias33 )</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THEN NULL</span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE a.ColumnAlias327</span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END ,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias328 = CASE WHEN EXISTS (</span><span style="font-size: medium;">SELECT TOP 1</span></span></p>
<p>&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;&nbsp;&nbsp;&nbsp;<br /><span style="color: #0000ff; font-size: medium;">&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;FROM&nbsp;&nbsp; DemoInfo b</span></p>
<p><span style="color: #0000ff;">&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;<span style="font-size: medium;">WHERE&nbsp; b.ColumnAlias328 =</span><span style="font-size: medium;">a.ColumnAlias328</span>&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size: medium;">AND a.ColumnAlias33 &gt; b.ColumnAlias33 )</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">&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; THEN NULL</span></p>
<p><span style="color: #0000ff; font-size: medium;">&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; ELSE</span><br /><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.ColumnAlias328</span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END ,</span></p>
<p><span style="color: #0000ff;"><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias329 = CASE WHEN EXISTS (</span><span style="font-size: medium;">SELECT TOP 1</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">&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; FROM&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DemoInfo b&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;</span><br /><span style="color: #0000ff;"><span style="font-size: medium;">&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; WHERE&nbsp;&nbsp;&nbsp;&nbsp; b.ColumnAlias328 =</span><span style="font-size: medium;">a.ColumnAlias328</span>&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="font-size: medium;">AND a.ColumnAlias33 &gt; b.ColumnAlias33 )</span></span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; THEN NULL</span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE 1</span></p>
<p><span style="color: #0000ff; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; END ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias30 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias31 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias32 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias33 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias34 ,</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ColumnAlias60</span></p>
<p>&nbsp;&nbsp;&nbsp;<span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM&nbsp;&nbsp;&nbsp; DemoInfo a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p>
<p>&nbsp;<span style="font-size: medium;">在客户环境中，每次运行语句时，动态视图中的信息都需要更新，所以等于每次视图都会被重建。接下来我们需要去看一下对应的执行计划。</span><br /><span style="font-size: medium;"><br />首先我们发现在执行计划中并不存在并行。并行需要额外的CPU开销来支持多核之间的同步。那么也就说明客户环境中没有这部分额外的开销。<br /><br /></span><span style="font-size: medium;">那么之后，我们应该去关注有没有Scan count（参考文档：<a href="https://blogs.msdn.com/b/sqlserverfaq/archive/2010/09/14/scan-count-meaning-in-set-statistics-io-output.aspx">https://blogs.msdn.com/b/sqlserverfaq/archive/2010/09/14/scan-count-meaning-in-set-statistics-io-output.aspx</a>）较多的表，来定位问题是否由某张表所导致的。然而在这个案例中我们有多张表的scan count 都比较高。<br /><br /></span><span style="font-size: medium;">另外执行计划中还有一个参数叫做 "Total </span><span style="font-size: medium;">Subtree cost", 这个是语句优化器在执行语句前对于执行计划中对应分支所需CPU,</span><span style="font-size: medium;">I/O, 内存所需成本的一个计算结果。我们可以通过这个参数来去判定哪一部分使用了较多的成本。</span><span style="font-size: medium;">（注意：对于实例之间成本的比较，使用这个参数并不准确）。由于篇幅的关系，这里对执行计划做了一个简化：</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8231.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8231.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8231.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8231.1.png" alt="" width="786" height="420" border="0" /></a></p>
<p><span style="font-size: medium;">有趣的是我们发现在复杂的执行计划中包含了四个完全相同的 "nest </span><span style="font-size: medium;">loops" Inner Join. 他们四个的 "Total Subtree </span><span style="font-size: medium;">cost"之和约有 1490， 而整个语句的cost</span><span style="font-size: medium;">为1969。尽管这个参数仅为SQL Server 语句优化器的计算值，而并非实际执行情况的精确反应，但足以说明这四个nest loops是整个语句执行成本的主要构成。<br /><br /></span><span style="font-size: medium;">因为四个部分的高度一致，我们很容易找到对应的语句是之前高亮的四条使用&ldquo;case when </span><span style="font-size: medium;">exists"的短句。当使用 &ldquo;case when exist" 这个短句时，执行计划必须使用半连接（left semi join)，而半连接又只能使用Nest </span><span style="font-size: medium;">loop。在客户环境中，nest loop join 是一个结果集对自身做join， 且结果集较大，所以使用nest loop join 开销非常大。然而对于这种固有的设计我们无法通过简单的加索引或加hint去调优语句。唯一的方式就是客户结合自己的具体业务需求重写语句而避免使用 &ldquo;case when exits"的短句。</span></p>
<p><span style="font-size: medium;">&nbsp;这就是今天的分享，更多SQL Server案例学习请持续关注本博客的更新。</span></p>]]></content:encoded>
    </item>
    <item>
      <title>SQL Server性能问题案例解析 （1）</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/sql-server-1-2</link>
      <pubDate>Thu, 25 Jun 2015 00:27:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/06/25/sql-server-1-2/</guid>
      <description><![CDATA[今天的博客将分享一个死锁的案例。阅读本文之前，需要对SQL Server的锁，事务，隔离级别有基本的了解。网络中有很多文章，我就不在这里复述了。
SQL Server中有一个叫做deadlock...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: medium;">今天的博客将分享一个死锁的案例。阅读本文之前，需要对SQL Server的锁，事务，隔离级别有基本的了解。网络中有很多文章，我就不在这里复述了。<br /></span></p>
<p><span style="font-size: medium;">SQL Server中有一个叫做deadlock monitor的线程，会定期去检测死锁。如果检测到死锁发生，deadlock </span><span style="font-size: medium;">monitor会选择一个session作为victim</span><span style="font-size: medium;">&nbsp;终止，从而解决死锁。在排查死锁时，我们通常建议客户开启trace flag 1222并抓取sql server trace用于分析。当开启了trace flag</span><span style="font-size: medium;">1222, SQL Server会将死锁的相关信息打印到ERROLROG中，包含信息有死锁的victim </span><span style="font-size: medium;">session, 各个参与死锁的session， 以及这些session正在等待的资源和锁。但如果同一时刻有多个死锁发生，这些死锁的信息会混杂在一起，很难区分。这时候如果有SQL trace，会相对容易很多。<br /><br /></span><span style="font-size: medium;">我们的案例就是这个情况&mdash;同时发生了很多死锁。首先我们要找出死锁中牵扯到的所有session，整理出一个deadlock框架。<br /><br /></span><span style="font-size: medium;">这是sql trace的一个截图</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8308.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8308.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8308.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8308.1.png" alt="" border="0" /></a><br />&nbsp;</p>
<p><span style="font-size: medium;">我们可以看到，session 71和session 121都在等待资源6cd5adef219d。<br /></span></p>
<p><span style="font-size: medium;">打开 SQL Server ERRORLOG，我们可以得知，当时的deadlock </span><span style="font-size: medium;">victim session的隔离级别， session id和等待资源。 deadlock </span><span style="font-size: medium;">victim是session 71。</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4087.2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4087.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4087.2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4087.2.png" alt="" width="885" height="76" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">ERRORLOG里也记录了session 71当时在等待什么资源，以及当时资源的的owner。对于session 71，我们可以得出如下信息：</span></p>
<p><span style="font-size: medium;">session id :71</span></p>
<p><span style="font-size: medium;">Process id: process107bdf4cf8</span></p>
<p><span style="font-size: medium;">isolation level:read committed</span></p>
<p><span style="font-size: medium;">status=suspened</span></p>
<p><span style="font-size: medium;">wait resource: 6cd5adef219d</span></p>
<p><span style="font-size: medium;">Resource-list关键字记录了当时涉及的资源等待情况，source owner，resource waiters以及等待的锁类型。</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/3301.3.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/3301.3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/3301.3.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/3301.3.png" alt="" width="1070" height="92" border="0" /></a></p>
<p><span style="font-size: medium;">我们可以看到，当时session 71在成为deadlock vicitm 前处于等待状态（requestType=wait），请求的lock mode为更新锁(U)。而process107b591c38是当时资源的所有者(owner id)，并且lock mode为U锁。</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">根据这个信息，我们就要可以查找process107b591c38的具体情况了，搜索process107b591c38关键字，得到如下信息：</span></p>
<p><span style="font-size: medium;">session id :98</span></p>
<p><span style="font-size: medium;">Process id:process107b591c38</span></p>
<p><span style="font-size: medium;">isolation level:read committed</span></p>
<p><span style="font-size: medium;">status=suspened</span></p>
<p><span style="font-size: medium;">wait resource: 73da75056a30</span></p>
<p><span style="font-size: medium;">own resource:</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/7610.4.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/7610.4.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/7610.4.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/7610.4.png" alt="" width="794" height="52" border="0" /></a></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">类似地，我们也可以得到session 98正在等待什么， 从而推理出整个deadlock chain。 具体的步骤和之前的方法相同，我就不一一列出了。以下是整个死锁的框架。</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">session id :71</span></p>
<p><span style="font-size: medium;">Process id: process107bdf4cf8</span></p>
<p><span style="font-size: medium;">isolation level:read committed</span></p>
<p><span style="font-size: medium;">status=suspened</span></p>
<p><span style="font-size: medium;">wait resource: KEY: 6:72057594045333504 (6cd5adef219d)</span></p>
<p><span style="font-size: medium;">own resource: KEY: 6:72057594045333504 (6cd5adef219d)</span></p>
<p><span style="font-size: medium;">blocked by: session 98</span></p>
<p><span style="font-size: medium;">block sessoin: 121</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">session id :98</span></p>
<p><span style="font-size: medium;">Process id:process107b591c38</span></p>
<p><span style="font-size: medium;">isolation level:read committed</span></p>
<p><span style="font-size: medium;">status=suspened</span></p>
<p><span style="font-size: medium;">wait resource: KEY: 6:72057594045333504 (73da75056a30)</span></p>
<p><span style="font-size: medium;">own resource: KEY: 6:72057594045333504 6cd5adef219d</span></p>
<p><span style="font-size: medium;">blocked by:sessoin 123</span></p>
<p><span style="font-size: medium;">block sessoin:71</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">session id : 123</span></p>
<p><span style="font-size: medium;">Process id: process107b5b9868</span></p>
<p><span style="font-size: medium;">isolation level:read committed</span></p>
<p><span style="font-size: medium;">status=suspened</span></p>
<p><span style="font-size: medium;">wait resource: KEY: 6:72057594045333504&nbsp; 73da75056a30</span></p>
<p><span style="font-size: medium;">own resource: KEY: 6:72057594045333504 73da75056a30</span></p>
<p><span style="font-size: medium;">blocked by 121</span></p>
<p><span style="font-size: medium;">block sessoin: 98</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">spid=121</span></p>
<p><span style="font-size: medium;">Process id: process107da05c38</span></p>
<p><span style="font-size: medium;">isolation level:read committed</span></p>
<p><span style="font-size: medium;">status=suspened</span></p>
<p><span style="font-size: medium;">waitresource=KEY: 6:72057594045333504 (6cd5adef219d)</span></p>
<p><span style="font-size: medium;">own resource:KEY: 6:72057594045333504 (73da75056a30)</span></p>
<p><span style="font-size: medium;">blocked by: session 71</span></p>
<p><span style="font-size: medium;">block sessoin:123</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/5554.5.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/5554.5.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/5554.5.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/5554.5.png" alt="" width="314" height="264" border="0" /></a></p>
<p><span style="font-size: medium;">这些语句都在等待同一个表上的资源，下面是这张表的定义：</span></p>
<p><span style="font-size: medium;">Column_name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">Type&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">Computed&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;</span><span style="font-size: medium;">Length&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Prec</span></p>
<p><span style="font-size: medium;">--------------------------------------------------------------------------------------------------------</span></p>
<p><span style="font-size: medium;">ENTITY_NAME&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">no&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;</span><span style="font-size: medium;">10&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p>
<p><span style="font-size: medium;">OTHER_KEY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">char&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">no&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;</span><span style="font-size: medium;">10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p>
<p><span style="font-size: medium;">SYS_GENERATED_ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">decimal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">no&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;</span><span style="font-size: medium;">9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 18&nbsp;</span></p>
<p><span style="font-size: medium;">MAX_FOR_RANGE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">decimal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-size: medium;">&nbsp;&nbsp;no&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;</span><span style="font-size: medium;">9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 10&nbsp;</span></p>
<p><span style="font-size: medium;">MAX_FOR_ENTITY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">decimal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">no&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;</span><span style="font-size: medium;">9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 18&nbsp;</span></p>
<p><span style="font-size: medium;">WARNING_LEVEL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">decimal&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">no&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;</span><span style="font-size: medium;">&nbsp;&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">18&nbsp;</span></p>
<p>&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;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p><span style="font-size: medium;">index_name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">index_description&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;">Index_keys&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></p>
<p><span style="font-size: medium;">--------------------------------------------------------------------------------------------------------</span></p>
<p><span style="font-size: medium;">CSSITLA1x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-size: medium;"><span style="background-color: #ffff00;">clustered, unique</span>, primary key located on&nbsp; </span><span style="font-size: medium;">PRIMARY&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="background-color: #ffff00;">ENTITY_NAME, OTHER_KEY<br /></span></span></p>
<p><span style="font-size: medium;">下面是这些session正在执行的语句：</span><br /><span style="font-size: medium;"><br />71</span></p>
<p><span style="font-size: medium;">exec sp_executesql N'SELECT</span><br /><span style="font-size: medium;">SYS_ID_CNTL_TBL01."ENTITY_NAME",SYS_ID_CNTL_TBL01."OTHER_KEY",SYS_ID_CNTL_TBL01."SYS_GENERATED_ID",SYS_ID_CNTL_TBL01."MAX_FOR_RANGE",SYS_ID_CNTL_TBL01."MAX_FOR_ENTITY",SYS_ID_CNTL_TBL01."WARNING_LEVEL"</span><br /><span style="font-size: medium;">FROM "SYS_ID_CNTL_TBL" SYS_ID_CNTL_TBL01 WITH (UPDLOCK) WHERE</span><br /><span style="font-size: medium;">(SYS_ID_CNTL_TBL01."<span style="background-color: #ffff00;">ENTITY_NAME</span>" = @0 AND</span><br /><span style="font-size: medium;">SYS_ID_CNTL_TBL01."<span style="background-color: #ffff00;">OTHER_KEY</span>" = @1)',N'@0 nvarchar(10),@1</span><br /><span style="font-size: medium;">nvarchar(10)',@0=N'VAC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br /><span style="font-size: medium;">',@1=N'74&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '<br /></span></p>
<p><span style="font-size: medium;">98</span></p>
<p><span style="font-size: medium;">exec sp_executesql N'UPDATE</span><br /><span style="font-size: medium;">"SYS_ID_CNTL_TBL" SET "SYS_GENERATED_ID" = @0 WHERE</span><br /><span style="font-size: medium;">"ENTITY_NAME" = @1 AND "OTHER_KEY" = @2',N'@0 float,@1</span><br /><span style="font-size: medium;">nvarchar(10),@2</span><br /><span style="font-size: medium;">nvarchar(10)',@0=223658585,@1=N'VAC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br /><span style="font-size: medium;">',@2=N'82&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">121</span></p>
<p><span style="font-size: medium;">exec sp_executesql N'SELECT</span><br /><span style="font-size: medium;">SYS_ID_CNTL_TBL01."ENTITY_NAME",SYS_ID_CNTL_TBL01."OTHER_KEY",SYS_ID_CNTL_TBL01."SYS_GENERATED_ID",SYS_ID_CNTL_TBL01."MAX_FOR_RANGE",SYS_ID_CNTL_TBL01."MAX_FOR_ENTITY",SYS_ID_CNTL_TBL01."WARNING_LEVEL"</span><br /><span style="font-size: medium;">FROM "SYS_ID_CNTL_TBL" SYS_ID_CNTL_TBL01 WITH (UPDLOCK) WHERE</span><br /><span style="font-size: medium;">(SYS_ID_CNTL_TBL01."ENTITY_NAME" = @0 AND</span><br /><span style="font-size: medium;">SYS_ID_CNTL_TBL01."OTHER_KEY" = @1)',N'@0 nvarchar(10),@1</span><br /><span style="font-size: medium;">nvarchar(10)',@0=N'VAC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><br /><span style="font-size: medium;">',@1=N'39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; '</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">123</span></p>
<p><span style="font-size: medium;">exec sp_executesql N'SELECT</span><br /><span style="font-size: medium;">SYS_ID_CNTL_TBL01."ENTITY_NAME",SYS_ID_CNTL_TBL01."OTHER_KEY",SYS_ID_CNTL_TBL01."SYS_GENERATED_ID",SYS_ID_CNTL_TBL01."MAX_FOR_RANGE",SYS_ID_CNTL_TBL01."MAX_FOR_ENTITY",SYS_ID_CNTL_TBL01."WARNING_LEVEL"</span><br /><span style="font-size: medium;">FROM "SYS_ID_CNTL_TBL" SYS_ID_CNTL_TBL01 WITH (UPDLOCK) WHERE</span><br /><span style="font-size: medium;">(SYS_ID_CNTL_TBL01."ENTITY_NAME" = @0 AND</span><br /><span style="font-size: medium;">SYS_ID_CNTL_TBL01."OTHER_KEY" = @1)',N'@0 nvarchar(10),@1</span><br /><span style="font-size: medium;">nvarchar(10)',@0=N'VAC&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ',@1=N'75</span><span style="font-size: medium;">'</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">我们可以看到死锁设计到的多个select语句都是相同的，它们指定了updlock hint，所以会申请U锁并需要等待U锁。这一般是业务需要，所以我们不能简单的去掉这个hint来解决问题。</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">接下来仔细分析下select语句，它在where中的条件涉及到ENTITY_NAME列和OTHER_KEY列，但如果我们查看表SYS_ID_CNTL_TBL的定义后会发现，ENTITY_NAME列和OTHER_KEY列组成了这张表的unique cluster index。 这样就保证了所有的语句只会返回一行，并且只会在需要查找的数据上加锁。但trace 1222显示这些session已经获得了一个U锁，当仍然去尝试获得另外一行数据的U锁。这是为什么呢？</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">我们再看一下从SQL trace中获得的执行计划：</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/5140.6.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/5140.6.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/5140.6.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/5140.6.png" alt="" width="667" height="63" border="0" /></a></p>
<p><span style="font-size: medium;">我们可以看到，这个语句确实只会返回一行，而且也用了Clustered Index Seek。但其中一步做了GetRangeThrouhConvert，这代表什么意思呢？我们在过去的博客中对此做过讲解，请参考<a href="https://blogs.msdn.com/b/apgcdsd/archive/2012/04/20/sql-server-2008.aspx">https://blogs.msdn.com/b/apgcdsd/archive/2012/04/20/sql-server-2008.aspx</a>。<br /></span><span style="font-size: medium;"><br />我们可以看到sp_executesql里指定的参数类型为nvarchar(),而ENTITY_NAME列和OTHER_KEY列的实际类型为varchar()。这样便使得SQL </span><span style="font-size: medium;">Server 要做一个数据类型转换，从而查询更多的本来不需要的行。那为什么程序会将参数类型设为nvarchar()呢？我们和客户进一步沟通后发现，客户的程序是Java, 并使用Microsoft JDBC driver, 这个 driver 会将客户端发过来的 character data 默认都声明成&nbsp; nvarchar()。<br /><br /></span><span style="font-size: medium;">如何改变这个行为呢？Microsoft JDBC drive链接字符中可以设定一个叫做sendStringParametersAsUnicode 的属性，它默认为true, </span><span style="font-size: medium;">只要把它设置为false, 那问题就解决了！客户端发来的参数将会声明成varchar()，这样我们就不会再做数据类型转换了，那Select语句需要查询的数据就不会重叠，自然也就不会发生死锁了。类似问题也可以参考这个博客<a href="https://blogs.msdn.com/b/sqlcat/archive/2010/04/05/character-data-type-conversion-when-using-sql-server-jdbc-drivers.aspx">https://blogs.msdn.com/b/sqlcat/archive/2010/04/05/character-data-type-conversion-when-using-sql-server-jdbc-drivers.aspx</a></span><span style="font-size: medium;"><br /><br />这就是今天的分享，更多SQL Server案例学习请持续关注本博客的更新。</span></p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>SQL Server连接问题案例解析（3）</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/sql-server3-2</link>
      <pubDate>Wed, 13 May 2015 00:06:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/05/13/sql-server3-2/</guid>
      <description><![CDATA[本文是SQL Server 连接问题案例解析系列的最后一个博文，在今天的案例中，除了分析Netmon日志，还会分享一些分析ODBC...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #000000; font-size: medium;">本文是SQL Server 连接问题案例解析系列的最后一个博文，在今天的案例中，除了分析Netmon日志，还会分享一些分析ODBC Trace的经验。</span></p>
<p><span style="color: #000000; font-size: medium;">首先来介绍一下这个案例中客户遇到的问题：</span></p>
<p><span style="color: #000000; font-size: medium;">客户在Linux服务器上使用UNIXODBC2.3.0将客户端连接到SQL Server数据库。当客户端连接运行在同一个实例中的非镜像数据库时，没有任何问题发生。但如果客户端连接镜像数据库，则会出现以下报错：</span></p>
<p><span style="color: #003366; font-size: small;">client=n/a (n/a) unixODBC-2.3.0 64-bit </span><span style="color: #003366; font-size: small;">/ab/home/misc/64/unixODBC/lib/libodbc.so</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB00001): Failed connecting to the database &lt;ALGO_PROD&gt;.</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB00001):</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB16000): ODBC Error</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB16000): SQLCODE: 20020</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB16000): SQLSTATE: 08S01</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB16000): MESSAGE:<span style="background-color: #ffff00;"> [unixODBC][FreeTDS][SQL </span></span><span style="color: #003366; font-size: small; background-color: #ffff00;">Server]Bad token from the server: Datastream processing out of sync</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB16000): ODBC Error</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB16000): SQLCODE: 0</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB16000): SQLSTATE: 08001</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB16000): MESSAGE:<span style="background-color: #ffff00;"> [unixODBC][FreeTDS][SQL </span></span><span style="color: #003366; font-size: small; background-color: #ffff00;">Server]Unable to connect to data source</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB00067): Current DB Environment:</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(DB00067):</span><br /><br /><span style="color: #003366; font-size: small;">ABINITIO(*): Database Package Version 3-1-6-4-e11-1</span></p>
<p><span style="color: #000000; font-size: medium;">其中值得注意的是应用程序运行在Linux上，客户端使用了ODBC。那么在Linux上有几种方法连接SQL Server呢？第一种是通过JDBC；OLEDB Client没有Linux版本，而ODBC是一个标准的接口，所以第三方的ODBC是可以连接SQL Server的，所以另外一种方法就是客户这种使用第三方ODBC进行连接。</span></p>
<p><span style="color: #000000; font-size: medium;">接下来我们进行了几个基本的检查：</span></p>
<p><span style="color: #000000; font-size: medium;">1. 检查连接字符串，确认其中服务器名正确，其值为principal server；</span></p>
<p><span style="color: #000000; font-size: medium;">2. 如果客户端使用的是OLEDB或.net的provider，我们在连接字符串中可以指定failover partner，而在客户的连接字符串中，没有写failover partner，只写了principal server name；同时也确认，在连接时，数据库确实在principal server name中指定的服务器上运行。</span></p>
<p><span style="color: #000000; font-size: medium;">以上两个检查可以排查掉一些基本的错误，如错误的连接镜像数据库。</span></p>
<p><span style="color: #000000; font-size: medium;">3. 客户的连接超时设置为15秒，但错误信息会立即报出。这个现象是不是让大家想到了在案例2中介绍到的.Net Framework的bug造成的连接问题呢？难道ODBC也有这个bug吗？</span></p>
<p><span style="color: #000000; font-size: medium;">&nbsp;&nbsp;&nbsp; 为了进一步验证，我们将连接超时的设置改为120秒，但是错误还是会马上报出。当超时时间被调长，重试时间也会相应的增长（计算公式：RetryTime = </span><span style="color: #000000; font-size: medium;">PreviousRetryTime + ( 0.08 *LoginTimeout) ），而此处错误仍然立即出现，说明这个问题和案例2中的问题是没有关系的。</span></p>
<p><span style="color: #000000; font-size: medium;">为了进一步调查， </span><span style="color: #000000; font-size: medium;">我们在问题发生时，在principal </span><span style="color: #000000; font-size: medium;">server 和mirror server上抓取了Netmon日志。不管客户端是什么，我们分析Netmon日志的方法是一样的，使用客户端的IP address对principal server上收集到的Netmon日志进行过滤后，得到如下：</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8831.1.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8831.1.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8831.1.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8831.1.jpg" alt="" border="0" /></a><br />&nbsp;<br /> <span style="color: #000000; font-size: medium;">可以看到：</span></p>
<ol>
<li><span style="color: #000000; font-size: medium;">首先，客户端主动连接SQL Server，发了一个sync包到SQL Server；SQL Server收到sync包之后ack了这个包，告诉客户端这个包被收到了；客户端收到了SQL回复的包后又发送了一个包给SQL Server，告诉SQL Server之前回复的包已被收到了。这三个包保证了双向连接的通顺，这也就是我们常说的三次握手。三次握手之后在TCP层面通过就建立起了连接。</span></li>
<li><span style="color: #000000; font-size: medium;">顺序向下看，三次握手结束后，客户端发送了prelogin 包，并且SQL Server使用了TDS response 对这个包进行ack。客户端收到TDS Response之后，也再次ack了这个包。（TCP的一个重要特征就是所有发出的包，对方都会ack，对方发过来的包也是同理。）</span></li>
<li><span style="color: #000000; font-size: medium;">接下来客户端向服务端发送了一个TDS Data，之后就开始进行NTLM authentication了。可以看到服务端对收到challenge进行了response并返回SPID70（frame276），并且客户端也对这个response进行了ack（frame 277）。</span></li>
</ol>
<p><span style="color: #000000; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;看到这里为止我们会发现这时客户端已经连接上了SQL Server，但接下来发生的事情非常奇怪：</span></p>
<p><span style="color: #000000; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;客户端在ack response之后迅速发送了一个fin包（TCP:Flags=&hellip;A&hellip;F）结束了会话（frame278）。</span></p>
<p><span style="color: #000000; font-size: medium;">客户测试了若干次，而在Netmon 日志中，后续若干次的行为也都是一样的，都是客户端在ack NTLM response后结束会话。但由此也可以见，造成这个问题的原因应该是客户端。</span></p>
<p><span style="color: #000000; font-size: medium;">当查看客户的连接字符串时，我们发现连接字符串中有一个client trace的选项，打开这个选项后，连接时会在客户端生成了一个ODBC </span><span style="color: #000000; font-size: medium;">Trace。</span></p>
<p><span style="color: #000000; font-size: medium;">查看客户端trace时，我们首先可以定位到错误信息是"Unable to connect </span><span style="color: #000000; font-size: medium;">to data source"，在这个错误信息报出前，有TDS_INT_CANCEL(2)返回，继续向上查看日志，可以看到Changed query state from </span><span style="color: #000000; font-size: medium;">IDLE to DEAD。而在DEAD前客户端的最后一个动作是获取了一个值为53的token，获取之后状态就变成了DEAD:</span></p>
<p><span style="color: #003366; font-size: small;">token.c:337:looking for login token, got&nbsp; e3(ENVCHANGE)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:122:tds_process_default_tokens() marker is e3(ENVCHANGE)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:337:looking for login token, got&nbsp; 53()</span></p>
<p><span style="color: #003366; font-size: small; background-color: #ffff00;">token.c:122:tds_process_default_tokens() marker is 53()</span></p>
<p><span style="color: #003366; font-size: small; background-color: #ffff00;">util.c:156:Changed query state from IDLE to DEAD</span></p>
<p><span style="color: #003366; font-size: small;">util.c:331:tdserror(0x5de19d0, 0x5df9530, 20020, 0)</span></p>
<p><span style="color: #003366; font-size: small;">odbc.c:2270:msgno 20020 20003</span></p>
<p><span style="color: #003366; font-size: small;">util.c:361:tdserror: client library returned TDS_INT_CANCEL(2)</span></p>
<p><span style="color: #003366; font-size: small;">util.c:384:tdserror: returning TDS_INT_CANCEL(2)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:256:Unknown marker: 83(53)!!</span></p>
<p><span style="color: #003366; font-size: small;">login.c:466:login packet accepted</span></p>
<p><span style="color: #003366; font-size: small;">util.c:331:tdserror(0x5de19d0, 0x5df9530, 20002, 0)</span></p>
<p><span style="color: #003366; font-size: small;">odbc.c:2270:msgno 20002 20003</span></p>
<p><span style="color: #003366; font-size: small;">util.c:361:tdserror: client library returned TDS_INT_CANCEL(2)</span></p>
<p><span style="color: #003366; font-size: small;">util.c:384:tdserror: <span style="background-color: #ffff00;">returning TDS_INT_CANCEL(2)</span></span></p>
<p><span style="color: #003366; font-size: small;">mem.c:615:tds_free_all_results()</span></p>
<p><span style="color: #003366; font-size: small; background-color: #ffff00;">error.c:412:odbc_errs_add: "Unable to connect to data source"</span></p>
<p>&nbsp;</p>
<p><span style="color: #000000; font-size: medium;">继续向上查看客户端 Trace，会看到以下信息：</span></p>
<p><span style="color: #003366; font-size: small;">net.c:555:Received header</span></p>
<p><span style="color: #003366; font-size: small;">0000 </span><span style="color: #003366; font-size: small;">04 01 02 35 00 49 01 00-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|...5.I..|</span></p>
<p>&nbsp;</p>
<p><span style="color: #003366; font-size: small;">net.c:609:Received packet</span></p>
<p><span style="color: #003366; font-size: small;">0000 04 01 02 35 00 49 01 00-e3 35 00 01 13 41 00 6c |...5.I.. .5...A.l|</span></p>
<p><span style="color: #003366; font-size: small;">0010 00 67 00 6f 00 5f 00 43-00 6f 00 6c 00 6c 00 61 |.g.o._.C .o.l.l.a|</span></p>
<p><span style="color: #003366; font-size: small;">0020 00 74 00 65 00 72 00 61-00 6c 00 5f 00 52 00 65 |.t.e.r.a .l._.R.e|</span></p>
<p><span style="color: #003366; font-size: small;">0030 00 70 00 06 6d 00 61 00-73 00 74 00 65 00 72 00 |.p..m.a. s.t.e.r.|</span></p>
<p><span style="color: #003366; font-size: small;">&hellip;&hellip;.</span></p>
<p><span style="color: #000000; font-size: medium;">大家有没有觉得这部分输出有点眼熟呢？</span></p>
<p><span style="color: #000000; font-size: medium;">既然客户端总是在收到服务端的NTLM response后结束会话，那我们不妨返回Netmon把这个response包展开来看一看：</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/0143.2.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/0143.2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/0143.2.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/0143.2.jpg" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">此时大家会发现，之前觉得眼熟的信息原来是和Netmon中包的Hex Details信息非常相似。</span></p>
<p><span style="color: #000000; font-size: medium;">比较客户端Trace和Netmon包中的信息，会发现其实客户端是在分段读取包中的Token，每读到一部分，在trace中就会有一段相应的输出。在读到这个出错的&ldquo;53&rdquo;之前，客户端已经成功的读到了多个token，以以下trace为例：</span></p>
<p><span style="color: #003366; font-size: small;">token.c:337:looking for login token, got&nbsp; e3(ENVCHANGE)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:122:tds_process_default_tokens() marker is e3(ENVCHANGE)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:337:looking for login token, got&nbsp; ab(INFO)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:122:tds_process_default_tokens() marker is ab(INFO)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:2588:tds_process_msg() reading message 5701 from server</span></p>
<p><span style="color: #003366; font-size: small;">token.c:2661:tds_process_msg() calling client msg handler</span></p>
<p><span style="color: #003366; font-size: small;">odbc.c:2270:msgno 5701 20003</span></p>
<p><span style="color: #003366; font-size: small;">token.c:2674:tds_process_msg() returning TDS_SUCCEED</span></p>
<p><span style="color: #003366; font-size: small;">token.c:337:looking for login token, got&nbsp; e3(ENVCHANGE)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:122:tds_process_default_tokens() marker is e3(ENVCHANGE)</span></p>
<p><span style="color: #003366; font-size: small;">token.c:2419:tds_process_env_chg(): 5 bytes of collation data received</span></p>
<p><span style="color: #003366; font-size: small;">token.c:2420:tds-&gt;collation was</span></p>
<p><span style="color: #003366; font-size: small;">0000 00 00 00 00 00&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; |.....|</span></p>
<p>&nbsp;</p>
<p><span style="color: #003366; font-size: small;">iconv.c:988:setting server single-byte charset to "CP1252"</span></p>
<p><span style="color: #003366; font-size: small;">token.c:2430:tds-&gt;collation now</span></p>
<p><span style="color: #003366; font-size: small;">0000 09 04 d0 00 34&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; |....4|</span></p>
<p>&nbsp;</p>
<p><span style="color: #000000; font-size: medium;">其实这一段对应的就是包中collation的token：</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/7028.3.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/7028.3.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/7028.3.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/7028.3.jpg" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">那么collation之后值为&ldquo;53&rdquo;的token到底是什么呢？展开查看它的详细信息，发现这是一个Real Time Log Shipping，Real Time Log Shipping就是指Mirror：</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/1004.4.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/1004.4.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/1004.4.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/1004.4.jpg" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">也就是说，当客户端读到Mirror的token时无法识别，因此客户端认为这是一个有问题的包，就把连接finish掉了。</span></p>
<p><span style="color: #000000; font-size: medium;">与成功连接生成的trace进行比较（客户端可以成功连接未配置镜像的数据库），会发现在好的连接的trace中，没有读取&ldquo;53&rdquo;这部分内容，读取完collation之后就继续读取了包中后续的内容。</span></p>
<p><span style="color: #000000; font-size: medium;">结论：当目标数据库使用了数据库镜像时，SQL Server会在响应的TDS 包中返回额外的信息，告诉客户端这是一个镜像数据库。但客户端无法识别这部分信息，认为这是一个错误的包，因而结束了连接。</span></p>
<p><span style="color: #000000; font-size: medium;">原因：</span></p>
<p><span style="color: #000000; font-size: medium;">在微软官方文档中有明确指出Microsoft ODBC Driver 11 </span><span style="color: #000000; font-size: medium;">for SQL Server on Linux不支持数据库镜像：</span></p>
<p><span style="color: #000000; font-size: medium;">The programming </span><span style="color: #000000; font-size: medium;">features of the Microsoft ODBC Driver 11 for SQL Server on Linux are based on </span><span style="color: #000000; font-size: medium;">ODBC in SQL Server Native Client (<a href="https://go.microsoft.com/fwlink/?LinkID=134151"><span style="color: #000000;">SQL Server Native Client (ODBC)</span></a>). SQL Server Native Client is based on ODBC in Windows </span><span style="color: #000000; font-size: medium;">Data Access Components (<a href="https://go.microsoft.com/fwlink/?LinkID=45250"><span style="color: #000000;">ODBC Programmer's Reference</span></a>).</span></p>
<p>&nbsp;<span style="color: #000000; font-size: medium;"><a title="Click to collapse. Double-click to collapse all." href="javascript:void(0)"><span style="color: #000000;"><strong>Features That Are <span style="background-color: #ffff00;">Not Available</span></strong></span></a><strong>：</strong></span></p>
<p><span style="color: #000000; font-size: medium;">The following </span><span style="color: #000000; font-size: medium;">features are not available in this release of the ODBC driver on Linux: <a href="https://technet.microsoft.com/en-us/library/hh568445(v=sql.110).aspx"><span style="color: #000000;">https://technet.microsoft.com/en-us/library/hh568445(v=sql.110).aspx</span></a></span></p>
<ul>
<li><span style="color: #000000; font-size: medium;">bulk copy </span><span style="color: #000000; font-size: medium;">functions (bcp_batch, for example)</span></li>
<li><span style="color: #000000; font-size: medium;">distributed transactions </span><span style="color: #000000; font-size: medium;">(SQL_ATTR_ENLIST_IN_DTC attribute is not supported)</span></li>
<li><span style="color: #000000; font-size: medium; background-color: #ffff00;">database mirroring</span></li>
<li><span style="color: #000000; font-size: medium;">FILESTREAM</span></li>
<li><span style="color: #000000; font-size: medium;">profiling ODBC </span><span style="color: #000000; font-size: medium;">driver performance, discussed in <a href="https://go.microsoft.com/fwlink/?LinkId=234099"><span style="color: #000000;">SQLSetConnectAttr</span></a>, the following performance-related connection </span><span style="color: #000000; font-size: medium;">attributes: </span>
<ul>
<li><span style="color: #000000; font-size: medium;">SQL_COPT_SS_PERF_DATA</span></li>
<li><span style="color: #000000; font-size: medium;">SQL_COPT_SS_PERF_DATA_LOG</span></li>
<li><span style="color: #000000; font-size: medium;">SQL_COPT_SS_PERF_DATA_LOG_NOW</span></li>
<li><span style="color: #000000; font-size: medium;">SQL_COPT_SS_PERF_QUERY</span></li>
<li><span style="color: #000000; font-size: medium;">SQL_COPT_SS_PERF_QUERY_INTERVAL</span></li>
<li><span style="color: #000000; font-size: medium;">SQL_COPT_SS_PERF_QUERY_LOG</span></li>
</ul>
</li>
</ul>
<p><span style="color: #000000; font-size: medium;">UNIXODBC </span><span style="color: #000000; font-size: medium;">2.3.0也很可能不支持数据库镜像。在客户与第三方确认后，这一点得到了证实。这个问题的根本原因就是UNIXODBC2.3.0不支持SQL Server数据库镜像。</span></p>
<p><span style="color: #000000; font-size: medium;">解决方案：</span></p>
<p><span style="color: #000000; font-size: medium;">通过使用JDBC driver在Linux服务器上连接使用了镜像的SQL Server数据库。关于Microsoft JDBC driver对与数据库镜像的支持信息，可以参考以下官方文档：</span></p>
<p><span style="color: #000000; font-size: medium;"><em>Database mirroring is primarily a software solution for increasing database availability and data redundancy. <span style="background-color: #ffff00;">The Microsoft SQL Server JDBC Driver provides implicit support for database mirroring</span>, so that the developer does not need to write any code or take any other action when it has been configured for the database</em>.</span></p>
<p><span style="color: #000000; font-size: medium;">Using Database Mirroring (JDBC)<a href="https://technet.microsoft.com/en-us/library/aa342332(v=sql.105).aspx"><span style="color: #000000;">https://technet.microsoft.com/en-us/library/aa342332(v=sql.105).aspx</span></a></span></p>
<p><span style="color: #000000; font-size: medium;">这就是今天的分享，之后我们将会发布关于SQL Server性能案例解析的系列，请持续关注本博客的更新。</span></p>]]></content:encoded>
    </item>
    <item>
      <title>AzureML中的回归</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/azureml</link>
      <pubDate>Fri, 08 May 2015 01:33:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/05/08/azureml/</guid>
      <description><![CDATA[在Microsoft Azure Machine Learning中提供了以下几种回归模型：

贝叶斯线性回归 Bayesian Linear Regression
提升决策树回归...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #000000; font-size: medium;">在Microsoft Azure Machine Learning中提供了以下几种回归模型：</span></p>
<ol>
<li><span style="color: #000000; font-size: medium;">贝叶斯线性回归 Bayesian Linear Regression</span></li>
<li><span style="color: #000000; font-size: medium;">提升决策树回归 Boosted Decision Tree Regression</span></li>
<li><span style="color: #000000; font-size: medium;">决策森林回归 Decision Forest Regression</span></li>
<li><span style="color: #000000; font-size: medium;">快速森林分位回归 Fast Forest Quantile </span><span style="color: #000000; font-size: medium;">Regression</span></li>
<li><span style="color: #000000; font-size: medium;">线性回归 Linear Regression</span></li>
<li><span style="color: #000000; font-size: medium;">神经网络回归 Neural Network Regression</span></li>
<li><span style="color: #000000; font-size: medium;">有序回归 Ordinal Regression</span></li>
<li><span style="color: #000000; font-size: medium;">泊松回归 Poisson Regression</span></li>
</ol>
<p><span style="color: #000000; font-size: medium;">那什么叫回归呢？在统计分析中，回归是研究一个随机变量Y对于另一个(X)或一组(X1, </span><span style="color: #000000; font-size: medium;">X2, &hellip;, Xk)变量的相依关系的统计分析方法。我们通常把X1, X2等叫做自变量，在机器学习里又叫做Feature（特征），而又把Y叫做因变量，也就是我们希望预测分析的部分。Y一般都是数值，是连续的，而在分类中我们预测的部分通常只有个别的几个值/类， 所以我们可以了解回归Regression与分类Classification的差别。在回归里，自变量可以是数值型的也可以是分类型的，而因变量是数值的。</span></p>
<p><span style="color: #000000; font-size: medium;">回归模型就是构造一个从x到y的映射关系。最简单的回归情形是当单个因变量和单个自变量为线性关系时，也就是一元线性回归（Linear </span><span style="color: #000000; font-size: medium;">Regression），通常的模型就是Y=a+bX+&epsilon;, 即在二维坐标上是一条直线，a是直线的截距，而b为直线的斜率。&epsilon;为随机误差（通常假定随机误差的均值为0）。通过获取样本数据，我们可以把这些点画成散点图，然后求解对应的系数a和b的值，这样就可以用一条直线来代表这个数据模型。当有新的自变量值输入到模型，我们就可以通过这个模型计算出因变量值从而进行预测。线性回归当然也可以是多元的，就是有多个X，互相之间是独立的。除了线性回归，还有非线性回归，也就是曲线或者曲面的回归。比如我们可以通过S型函数来进行逻辑回归。而更一般的情况是多元的情况。比如贝叶斯线性回归假设随机变量的概率分布近似于高斯分布也就是正态分布来描述，通过最大后验概率来求解回归问题。而泊松回归则假设因变量Y是泊松分布，并假设它期望值的对数可以被未知参数的线性组合建模。</span></p>
<p><span style="color: #000000; font-size: medium;">决策树本来是应用最广的分类算法之一。决策树可以表示成多个If-Else的规则。它其实是将空间用超平面进行划分的一种方法，每次分割的时候，都将当前的空间一分为二，比如说下面的决策树：</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/3755.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/3755.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/3755.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/3755.1.png" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">我们可以在二维坐标中画出来：</span><br />&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/3858.2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/3858.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/3858.2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/3858.2.png" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">这样我们可以在一个待分类的样本实例进行决策的时候根据2个特征(x,y)的取值来划分到对应的一个叶子节点，得到分类结果。这就是决策树分类的过程。而提升（Boosting）是属于模型组合的方法之一，通过组合效果可以比单个模型更好。Boosting就是用弱分类器先分类，然后把上次分错的数据权重提高一点，然后再分类，这样最终得到的模型效果比较好。在决策树上运用这个思想就可以达到更好的效果。而回归树选择变量的标准用残差平方和。在决策树的根部残差平方和就是回归的残差平方和。然后选择一个特征，使得通过这个进行分类后的两部分的分别的残差平方和的和最小。然后在分叉的节点再利用这个准则进行分类，生长成一个树。而在这个基础上，我们还要进行剪枝，通过训练样本来进行评估，如果被减的树中得到的残差平方和缩小了，那么剪枝就是有效的，否则就不剪。在机器学习中，随机森林包含多个决策树， 输出的类别是由个别数输出的类别的众数而定。而决策森林结合了随机森林和随机子空间方法来建造决策树的集合，它引入了模型组合的另外一个重要方法，也就是Bagging。对于每个节点会随机选择m个特征，根据这m个特征计算其最佳分裂方式。这里每棵树的成长是不会剪枝的。</span></p>
<p><span style="color: #000000; font-size: medium;">在统计里面，有序回归是一类回归分析用来预测一个有序变量的。有序变量可以这样理解：比如我们评价客户满意度从1分到9分，1到3代表&rdquo;非常不满意&ldquo;，4到5分表示&rdquo;不满意&ldquo;，6分到7分代表&rdquo;满意&ldquo;，8和9代表&ldquo;非常满意&ldquo;。这就是有序变量。</span></p>
<p><span style="color: #000000; font-size: medium;">而人工神经网络回归可用于非线性回归，是一种大规模并行非线性系统，具有良好的非线性映射能力，强大的解决问题的能力和实际推广能力。它是一组算法来模拟大脑的工作。神经网络算法有很多种，最主要的是backpropagation，又叫多层感知器。通常有三层网络：</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8080.3.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8080.3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8080.3.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8080.3.png" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">最左边的是输入层，中间是隐藏层，而右边是输出层。当然我们可以有更多的隐藏层。一般输入的节点数相当于独立自变量的数量。而输出节点数为因变量的数量。而隐藏层的节点数就比较复杂。在训练阶段，我们给网络喂一组样本。在向前传播过程中，在隐藏层和输出层的节点会计算一个加权的输入总和，然后用这个总和通过一个激活函数来计算它的输出。通常我们用S型函数，或者高斯，甚至线性函数来作为激活函数。当输出计算好了以后，向后传播的步骤就开始了。在这个阶段，算法会计算预测值跟实际值的误差。使用梯度下降的方法，它调节所有回传误差连接的权重。这些权重的调整能够减少下次的误差。通过一系列样本的列举，最终神经网络形成对应的模型。在这其中，有2个参数比较重要。一个是学习的效率(learning rate)。如果效率太低，那么列举就多，时间就长。而效率太高，可能很难找到局部极小值。另一个是关于隐藏节点数量。随着隐藏节点的数量增加，模型的精确度可增加，但却会造成过拟合。通常我们设定输入节点数的平方根作为起始值或者这个值在输入节点数和输出节点数之间比如(输入节点数+输出节点数)/3。通常只有在测试中才能调整到比较合适的值。</span></p>]]></content:encoded>
    </item>
    <item>
      <title>Storm介绍</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/storm</link>
      <pubDate>Fri, 08 May 2015 01:20:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/05/08/storm/</guid>
      <description><![CDATA[Apache...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #000000; font-size: medium;">Apache Storm是一个分布式的，容错的，开源的计算系统。它允许我们使用Hadoop来进行实时数据处理。Storm的解决方案还能保证数据都被处理，它有能力对首次处理不成功的数据进行重新处理。根据一些性能方面基准测试，Storm可以达到每个节点每秒处理超过百万的Tuple。</span></p>
<p><span style="color: #000000; font-size: medium;">那么为什么要用HDInsight里的Storm呢？在HDInsight服务里的Apache </span><span style="color: #000000; font-size: medium;">Storm是一个整合在Azure环境里的托管的集群。它提供了几个主要好处：</span></p>
<ol>
<li><span style="color: #000000; font-size: medium;">作为一个托管服务，它能够达到三个9 (99.9%)的高可用性</span></li>
<li><span style="color: #000000; font-size: medium;">它支持使用各种语言， Java, </span><span style="color: #000000; font-size: medium;">C$, Python等等。还可以混合语言，比如读的时候用Java，处理的时候用C#. 它使用了Trident的Java接口来创建Storm </span><span style="color: #000000; font-size: medium;">Topology，支持&ldquo;有且唯一&rdquo;的消息处理，事物性的数据存储持续化，和一组通用的流分析的操作。</span></li>
<li><span style="color: #000000; font-size: medium;">它提供了内建的动态扩展特点， 对一个HDInsight的集群进行扩展不会影响执行Storm </span><span style="color: #000000; font-size: medium;">Tology。</span></li>
<li><span style="color: #000000; font-size: medium;">Storm和其他Azure服务整合在一起，包括Event </span><span style="color: #000000; font-size: medium;">Hub，Azure </span><span style="color: #000000; font-size: medium;">Virtual Network, SQL 数据库， Blob storage, 和Document </span><span style="color: #000000; font-size: medium;">DB。可以用Azure&nbsp; Virtual Network把多个HDInsight </span><span style="color: #000000; font-size: medium;">Cluster能力整合起来，创建使用HDInsight </span><span style="color: #000000; font-size: medium;">HBase或者Hadoop的分析流水线。</span></li>
</ol>
<p><span style="color: #000000; font-size: medium;">HDInsight上的Storm非常容易准备，我们可以通过Auzre门户或者PowerShell来创建，只需要选取简单的几个参数，等上15分钟就可以创建完毕。如果我们使用Visual </span><span style="color: #000000; font-size: medium;">Studio, 那么HDInsight </span><span style="color: #000000; font-size: medium;">Tools for Visual Studio可以用来创建C#或者混合C#/Java的topology，然后提交到HDInsight集群中的Storm。HDInsight </span><span style="color: #000000; font-size: medium;">Tools for Visual Studio还提供了接口来监视和管理Storm topology。</span></p>
<p><span style="color: #000000; font-size: medium;">每个HDInsight集群里的Storm都提供了一个基于Web的仪表盘，我们可以用它来提交，监视，和管理所运行的Storm </span><span style="color: #000000; font-size: medium;">topology。Storm还通过Event </span><span style="color: #000000; font-size: medium;">Hub Spout提供了跟Azure </span><span style="color: #000000; font-size: medium;">Event Hub集成的功能。</span></p>
<p><span style="color: #000000; font-size: medium;">Storm可以保证每个收入的消息都被完全处理，即使数据的分析分散到几百个节点。</span></p>
<p><span style="color: #000000; font-size: medium;">Storm是跑在Hadoop的Yarn框架上的应用。同Hadoop的Job </span><span style="color: #000000; font-size: medium;">Tracker类似，Nimbus </span><span style="color: #000000; font-size: medium;">节点提供了类似的功能，它可以通过Zookeeper来把任务分配到其他节点。Zookeeper节点提供集群的协调并且提供Nimbus和工作节点上的Supervisor进程的通讯。如果有处理节点坏掉了，Nimbus会被通知到，然后它会把任务和相关数据交给其他节点来处理。缺省设置下Apache </span><span style="color: #000000; font-size: medium;">Storm有单个Nimbus节点，而HDInsight里的Storm有2个Nimbus节点。如果主节点失败了，集群会切换到从属节点。现在HDInsight支持动态调整工作节点的数量，就算是在处理数据的时候也可以进行动态调整。</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8053.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8053.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8053.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8053.1.png" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">那么Storm是如何来处理数据的呢？</span></p>
<p><span style="color: #000000; font-size: medium;">我们知道Hadoop是运行MapReduce作业的，而Storm是运行topology的。Storm集群包括2类节点：运行Nimbus的主节点，和运行Supervisor的工作节点。</span><br />&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8233.2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8233.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8233.2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8233.2.png" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">Nimbus是什么？它类似于Job Tracker, 主要负责把代码分发到集群中，把任务派发给虚拟机，然后监控是否有失败的状态。</span></p>
<p><span style="color: #000000; font-size: medium;">Supervisor呢？它运行在每个工作节点，负责启动和停止工作进程。</span></p>
<p><span style="color: #000000; font-size: medium;">工作进程执行topology的一部分。一个运行的topology会被分布到很多个工作进程。</span></p>
<p><span style="color: #000000; font-size: medium;">Topology定义了对数据流处理的计算图，也就是一个逻辑上的拓扑结构。不像MapReduce的作业，topology作为一个实时在Storm中运行的单位，会一直运行直到我们停止它。</span></p>
<p><span style="color: #000000; font-size: medium;">在Storm里的Stream(流)是Tuple的集合。流是由Spout和Bolt来生成的，而由Bolt来消费。</span></p>
<p><span style="color: #000000; font-size: medium;">那Tuple又是什么呢？Tuple是消息传递的基本单元，一个带类型的值的已经命名的表。我们可以想象Key-Value的配对，在这里因为字段名称已经事先定义好了，所以只需要值的列表就可以了。</span></p>
<p><span style="color: #000000; font-size: medium;">Spout是产生源数据流的组件，通常我们用它来从外部数据源读取数据，然后发射为数据流。</span></p>
<p><span style="color: #000000; font-size: medium;">Bolt呢？它是用来消费数据流的，提供对Tuple的处理，并且也可能发射数据流。我们可以在Bolt对数据进行想要的操作。Bolt也负责把数据写到外部存储，比如queue，HDInsight，HBase，Blob或者其他数据存储。</span></p>
<p><span style="color: #000000; font-size: medium;">另外Apache Thrift是为了可扩展的跨语言服务开发的一个软件框架，使得我们可以通过它在C++, </span><span style="color: #000000; font-size: medium;">Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, </span><span style="color: #000000; font-size: medium;">Smalltalk, 和其他语言间创建服务。Nimbus是一个Thrift的服务， 而topology是一个Thrift的定义，所以我们可以使用不同语言来开发Topology。</span></p>
<p>&nbsp;</p>
<p><span style="color: #000000; font-size: medium;">一个基本的Storm可以保证至少一次的处理，而Trident可以保证有且唯一次的处理。在流处理中通常有几种处理的模式。比如读取输入Tuple，发射0个或多个Tuple， 然后在执行最后回应输入tuple。这类模式可以用IBasicBolt来自动化。而Join的处理模式可能有不同的方式。比如，我们可以把多个流的每个tuple&nbsp; join起来成一个新的流。或者只join某个时间窗的一批tuple。这些都可以通过fieldsGrouping来实现。我们有时候会用这个办法来定义tuple如何引导到bolt。Batching模式可以通过集中方式来实现，比如在基本的Storm </span><span style="color: #000000; font-size: medium;">Java Topology里，我们可以用一个计数器来批处理X条tuple, 或者通过一个&rdquo;tick </span><span style="color: #000000; font-size: medium;">tuple&rdquo;来每X秒发射一个批次。Caching是可以加快处理速度的，我们可以考虑使用fieldsGroup来提高Cache </span><span style="color: #000000; font-size: medium;">lookup的命中率，使得包含field的tuple都会进到同一个进程里，这样可以避免不同进程间的重复的Cache。对于获取Top </span><span style="color: #000000; font-size: medium;">N的计算，我们可以并行计算top </span><span style="color: #000000; font-size: medium;">N，然后合并输出到一个全局值。我们可以用fieldsGrouping来导引到并行的Bolt上，使得数据根据字段值进行分区，然后引导到一个bolt再做全局的top </span><span style="color: #000000; font-size: medium;">N。</span></p>]]></content:encoded>
    </item>
    <item>
      <title>AzureML中的聚类</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/azureml-2</link>
      <pubDate>Fri, 08 May 2015 01:11:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/05/08/azureml-2/</guid>
      <description><![CDATA[聚类是一种无监督的机器学习。在聚类中，目标是为了把相似的对象归组到一起。通常聚类算法可以分成以下几类：

Partitioning分区：可以把数据集分成k个分区。每个分区对应于一个簇。
Hier...]]></description>
      <content:encoded><![CDATA[<p><span style="color: #000000; font-size: medium;">聚类是一种无监督的机器学习。在聚类中，目标是为了把相似的对象归组到一起。通常聚类算法可以分成以下几类：</span></p>
<ol>
<li><span style="color: #000000; font-size: medium;">Partitioning分区：可以把数据集分成k个分区。每个分区对应于一个簇。</span></li>
<li><span style="color: #000000; font-size: medium;">Hierarchical 分层：基于数据集，分层会通过自下而上或者自上而下地创建簇。在自下而上的方式中，算法开始把每个项分派给一个簇，在算法从层次网上移动的时候，它把个别相似的簇归并成更大的簇。这样一直继续下去知道所有的簇都归并到一个也就是层次的根节点。在自上而下的方式中，算法是把所有项目都归于一个簇，然后在每次反复的时候分成小的簇。</span></li>
<li><span style="color: #000000; font-size: medium;">Density 密度：该算法考虑邻居的密度，也就是项目数量。通常它用来找出有任意形状的簇。相反，分区依赖于距离的度量，所以生成的簇有普通的形状，比如球状。</span></li>
</ol>
<p><span style="color: #000000; font-size: medium;">在基于分区的聚类算法中，我们需要度量点和向量的距离。通常的度量方式有欧式距离，余弦距离，曼哈顿距离等等，在Azure </span><span style="color: #000000; font-size: medium;">Machine Learning中，K-Means Clustering支持欧式距离和余弦距离的度量。对2个点p1, p2来说，欧式距离就是这两点连线的线段长度。欧式距离也可以度量两个向量的距离。而对2个向量v1和v2来说，余弦距离就是v1和v2的角度的余弦。</span></p>
<p><span style="color: #000000; font-size: medium;">在聚类时使用的距离度量取决于聚类数据的类型。欧式距离对向量的度量量级是敏感的。比如说，尽管2个向量看上去很相似，特征的数量级会影响欧式距离的值。在这种情形下，用余弦距离可能更合适，因为余弦距离对数量级不敏感。2个向量之间的余弦角度是很小的。</span></p>
<p><span style="color: #000000; font-size: medium;">Azure Machine Learning中使用K-Means算法来聚类。这个算法过程是这样的：</span></p>
<ol>
<li><span style="color: #000000; font-size: medium;">从数据集随机选取k个项目作为初始中心。</span></li>
<li><span style="color: #000000; font-size: medium;">对剩下的其他项目，根据项目和簇中心的距离把他们分配给对应的簇。</span></li>
<li><span style="color: #000000; font-size: medium;">重新计算每个簇新的中心。</span></li>
<li><span style="color: #000000; font-size: medium;">重复步骤2和步骤3直到簇不再发生变化或者达到了最大的重复数。</span></li>
</ol>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/7776.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/7776.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/7776.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/7776.1.png" alt="" border="0" /></a>&nbsp;<br /><br /><span style="color: #000000; font-size: medium;">如图所示，这是一个K-Means的聚类，这里分成了3个簇，用三种颜色来标明。</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/1565.2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/1565.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/1565.2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/1565.2.png" alt="" border="0" /></a></p>
<p><br />&nbsp;<span style="color: #000000; font-size: medium;">如图所示，这是对于k=3的时候算法计算的过程。+号是每次计算的簇的中心。一次次降低了平均误差平方根变得越来越准确反应簇的中心。</span></p>
<p><span style="color: #000000; font-size: medium;">在K-Means Clustering模块中，它支持不同的簇中心的初始算法。这是通过Initialization属性来设置。我们可以用下面5种初始算法：</span></p>
<ol>
<li><span style="color: #000000; font-size: medium;">Default缺省的，就是选取起始的N个点作为初始中心。</span></li>
<li><span style="color: #000000; font-size: medium;">Random随机的，随机选取初始中心。</span></li>
<li><span style="color: #000000; font-size: medium;">K-Means++ 采用K-Means++的中心初始化。</span></li>
<li><span style="color: #000000; font-size: medium;">K-Means+Fast 在每次重复中选取最远的中心作为初始中心。</span></li>
<li><span style="color: #000000; font-size: medium;">Evenly 选取均匀的N个点作为初始中心。</span></li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>SQL Server连接问题案例解析（2）</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/sql-server2-2</link>
      <pubDate>Mon, 04 May 2015 00:07:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/05/04/sql-server2-2/</guid>
      <description><![CDATA[在本篇博文中，我将为大家介绍一个在使用数据库镜像功能时发生的连接超时问题。关于数据库镜像的关键概念和术语，在之前的博客数据库镜像故障转移后，.NET应用程序连接SQL Server...]]></description>
      <content:encoded><![CDATA[<p style="text-align: left;" align="center"><span style="font-size: medium;">在本篇博文中，我将为大家介绍一个在使用数据库镜像功能时发生的连接超时问题。关于数据库镜像的关键概念和术语，在之前的博客<a href="https://blogs.msdn.com/b/apgcdsd/archive/2015/04/07/net-sql-server.aspx">数据库镜像故障转移后，.NET应用程序连接SQL Server 超时（译文）</a>中已经有了详细的介绍，这里不再赘述，大家可以参考前文。</span></p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;"><span style="font-size: medium;">问题描述</span></p>
<p style="text-align: left;"><span style="font-size: medium;">========</span></p>
<p style="text-align: left;"><span style="font-size: medium;">客户想要在Lync上安装一些组件，在后端需要从英国站点向澳大利亚站点的SQL Server建立连接时会如下错误：</span><br /><span style="font-size: medium;"> <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4786.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4786.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4786.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4786.1.png" alt="" border="0" /></a></span></p>
<p style="text-align: left;"><span style="font-size: medium;">英国站点：</span></p>
<p style="text-align: left;"><span style="font-size: medium;">服务器: lyncdben01</span></p>
<p style="text-align: left;"><span style="font-size: medium;">澳大利亚站点：</span></p>
<p style="text-align: left;"><span style="font-size: medium;">服务器: lyncdbau01</span></p>
<p style="text-align: left;"><span style="font-size: medium;">在问题调查的过程中，我们分别收集到了连接成功时与问题发生时的Netmon 日志。从dump 文件中，得到了Powershell命令背后真正的连接字符串：</span></p>
<p style="text-align: left;"><span style="font-size: medium;"><strong>Data Source= lyncdbau01.group.local\lyncdbau01;Database=xds;Max Pool Size=4;Connection Reset&nbsp;=false;Enlist=false;IntegratedSecurity=true;Pooling=true;<span style="color: #ff0000;">Failover Partner= lyncdbau02.group.local\lyncdbau02;</span></strong></span></p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;"><span style="font-size: medium;">问题分析</span></p>
<p style="text-align: left;"><span style="font-size: medium;">=========</span></p>
<p><span style="font-size: medium;">1. 连接字符串很明确的告诉了我们，这是一个用于连接使用了镜像的数据库的连接字符串。如果一个连接尝试失败或者重试时间过期，则数据访问接口将尝试连接镜像的另一个伙伴。如果此时未打开连接，则数据访问接口还会尝试使用初始伙伴名称和故障转移伙伴名称，直到连接打开或登录期限超时。</span></p>
<p style="text-align: left;"><span style="font-size: medium;">重试时间为登录期限的某个百分比数。在后续的每轮中，连接尝试的重试时间会逐渐变大。在第一轮中，两次尝试的每次重试时间都是总登录时间的 8%。在后续的每轮中，重试算法会按相同的百分比增加最大重试时间。因此，前八次连接尝试的重试时间如下：</span></p>
<p style="text-align: left;"><span style="font-size: medium;"><strong>8%, 8%, 16%, 16%, 24%, 24%, 32%, 32%</strong></span></p>
<p style="text-align: left;"><span style="font-size: medium;">重试时间使用以下公式进行计算：</span></p>
<p style="text-align: left;"><span style="font-size: medium;"><strong>RetryTime = PreviousRetryTime + ( 0.08*LoginTimeout)</strong></span></p>
<p style="text-align: left;"><span style="font-size: medium;">其中，PreviousRetryTime 初始值为 0。</span></p>
<p style="text-align: left;"><span style="font-size: medium;">例如，如果使用默认的登录超时期限 15 秒，则LoginTimeout = 15。在这种情况下，前三轮中分配的重试时间如下：</span></p>
<table style="float: left;" border="1" cellpadding="0">
<tbody>
<tr>
<td>
<p align="center"><span style="font-size: medium;">轮次</span></p>
</td>
<td>
<p align="center"><span style="font-size: medium;">RetryTime 计算</span></p>
</td>
<td>
<p align="center"><span style="font-size: medium;">每次尝试的重试时间</span></p>
</td>
</tr>
<tr>
<td>
<p><span style="font-size: medium;">1</span></p>
</td>
<td>
<p><span style="font-size: medium;">0 +(0.08 * 15)</span></p>
</td>
<td>
<p><span style="font-size: medium;">1.2 秒</span></p>
</td>
</tr>
<tr>
<td>
<p><span style="font-size: medium;">2</span></p>
</td>
<td>
<p><span style="font-size: medium;">1.2 +(0.08 * 15)</span></p>
</td>
<td>
<p><span style="font-size: medium;">2.4 秒</span></p>
</td>
</tr>
<tr>
<td>
<p><span style="font-size: medium;">3</span></p>
</td>
<td>
<p><span style="font-size: medium;">2.4 +(0.08 * 15)</span></p>
</td>
<td>
<p><span style="font-size: medium;">3.6 秒</span></p>
</td>
</tr>
<tr>
<td>
<p><span style="font-size: medium;">4</span></p>
</td>
<td>
<p><span style="font-size: medium;">3.6 +(0.08 * 15)</span></p>
</td>
<td>
<p><span style="font-size: medium;">4.8 秒</span></p>
</td>
</tr>
</tbody>
</table>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;"><span style="font-size: medium;">下图说明了这些后续连接尝试的重试时间，每个重试时间均超时。</span></p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;"><span style="font-size: medium;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/1616.2.gif" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/1616.2.gif"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/1616.2.gif" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/1616.2.gif" alt="" width="421" height="200" border="0" /></a></span></p>
<p style="text-align: left;"><span style="font-size: medium;">对于默认的登录超时期限，分配给前三轮连接尝试的最长时间为14.4 秒。如果每次尝试都使用了它的全部分配时间，则在登录期限超时之前仅剩下 0.6 秒的时间。在这种情况下，第四轮的时间会缩短，仅允许使用初始伙伴名称进行最后的快速连接尝试。但是，连接尝试可能会在其分配的重试时间内失败，尤其是在稍后的轮次中。例如，接收网络错误可能会导致在重试时间到期之前尝试便已结束。如果较早的尝试因网络错误而失败，则可以为第四轮（还可能包括更多轮）提供更多的时间。</span></p>
<p style="text-align: left;"><span style="font-size: medium;">（<a href="https://msdn.microsoft.com/en-us/library/ms365783.aspx">https://msdn.microsoft.com/en-us/library/ms365783.aspx</a> ）</span></p>
<p><span style="font-size: medium;">2. 此时分析抓取到的Netmon日志会发现在问题发生时，客户端很快就close并reset了连接：</span></p>
<p style="text-align: left;"><span style="font-size: medium;"><strong>434&nbsp;&nbsp;&nbsp;&nbsp; 10:32:00 AM 3/4/2014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 19.5784779&nbsp;&nbsp; powershell.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lyncdben01&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lyndbaup01.tollgroup.local&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TCP&nbsp;&nbsp;&nbsp;&nbsp; TCP:Flags=...<span style="color: #ff0000; background-color: #ffff00;">A...F</span>, SrcPort=60709, DstPort=54994, PayloadLen=0, Seq=2129002479, Ack=1739112270, Win=256 (scale factor 0x8) = 65536 {TCP:75, IPv4:34}</strong></span></p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;"><span style="font-size: medium;"><strong>435&nbsp;&nbsp;&nbsp;&nbsp; 10:32:00 AM 3/4/2014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 19.6357220&nbsp;&nbsp; powershell.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lyndbaup01.group.local&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lyncdben01&nbsp;&nbsp; TCP&nbsp;&nbsp;&nbsp;&nbsp; TCP:Flags=...AP...,SrcPort=54994, DstPort=60709, PayloadLen=617, Seq=1739112270 - 1739112887,Ack=2129002479, Win=256 (scale factor 0x8) = 65536 {TCP:75, IPv4:34}</strong></span></p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;"><span style="font-size: medium;"><strong>436&nbsp;&nbsp;&nbsp;&nbsp; 10:32:00 AM 3/4/2014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 19.6357463&nbsp;&nbsp; powershell.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lyncdben01&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lyncdbau01.group.local&nbsp;&nbsp;&nbsp;&nbsp; TCP&nbsp;&nbsp;&nbsp;&nbsp; TCP:Flags=...<span style="color: #ff0000; background-color: #ffff00;">A.R</span>..,SrcPort=60709, DstPort=54994, PayloadLen=0, Seq=2129002480, Ack=1739112887,Win=0 (scale factor 0x8) = 0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {TCP:75,IPv4:34}</strong></span></p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;"><span style="font-size: medium;">&nbsp;问题原因</span></p>
<p style="text-align: left;"><span style="font-size: medium;">=========</span></p>
<p style="text-align: left;"><span style="font-size: medium;">这个问题实际上是由.Net Framework 3.5 或 .NET Framework 4 的一个已知问题造成的：</span></p>
<p style="text-align: left;"><span style="font-size: medium;"><a href="https://support.microsoft.com/en-us/kb/2605597/">https://support.microsoft.com/en-us/kb/2605597/</a></span></p>
<p style="text-align: left;"><span style="font-size: medium;">当使用镜像数据库中连接的重试算法时，数据提供程序将等待一个读（SniReadSync）调用完成。这个调用发送到后端运行SQL Server的服务器，并且等待时间会被计算为连接超时时间乘以0.08 。但是，如果响应慢并且第一次SniReadSync 调用在等待时间过期时未完成，数据提供程序会错误的将连接设置为了doomed</span><br /><span style="font-size: medium;">状态。</span><br /><br /><span style="font-size: medium;">注意：响应较慢问题在这种情况下可能由与服务端或网络的延迟触发。</span><br /><br /><br /><span style="font-size: medium;">解决方案</span></p>
<p style="text-align: left;"><span style="font-size: medium;">=========</span></p>
<p style="text-align: left;"><span style="font-size: medium;">这个已知问题已在.NET Framework 4.5.2中修复，因此对于.NET Framework 4，可以选择将其升级至4.5.2或更高版本来解决此问题。对于其他版本的. NET Framework，相应的修补程序也已经发布，可以通过安装相应的修补程序解决。详细信息，请参考：<a href="https://support.microsoft.com/en-us/kb/2605597/">https://support.microsoft.com/en-us/kb/2605597/</a></span><br /><br /><span style="font-size: medium;">这就是今天的分享，更多SQL Server案例学习请持续关注本博客的更新。</span></p>]]></content:encoded>
    </item>
    <item>
      <title>SQL Server 连接问题案例解析（1）</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/sql-server-1-3</link>
      <pubDate>Sun, 26 Apr 2015 23:36:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/04/26/sql-server-1-3/</guid>
      <description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Microsoft Network...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Microsoft Network Monitor（Netmon）是由微软发布的一款网络协议数据分析工具，利用Netmon可以捕获网络数据并进行查看和分析。在处理SQL Server 的连接问题时，Netmon常常会起到关键的作用。在本篇博文中，我将为大家分享一个通过使用 Netmon 解决的经典案例。</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个案例中，客户发现在客户端的 SQL Server Management Studio 中执行某一个Query时就会发生错误，错误信息是&ldquo;connection forcibly close by the remote server &rdquo;。 为了调查连接被关闭的原因，我们在客户端和服务端抓取了Netmon。</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在正式分析这个案例前，我们先来介绍一些有关Netmon的知识和使用技巧。</span></p>
<p style="padding-left: 30px;"><br /><span style="font-size: medium;"> <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/7343.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/7343.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/7343.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/7343.1.png" alt="" border="0" /></a></span><br /><span style="font-size: medium;">&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Netmon界面</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">1. 在Netmon界面中的Frame Summary 部分，我们首先可以看到Frame Number，不管我们在浏览时是否有设置filter，Frame Number的值是不会发生改变的，它相当于Frame的一个行号。</span></p>
<p><span style="font-size: medium;">2. 在左侧Network Conversation 中，我们会看到进程的name和ID，在示例中即为Ssms.exe和3352。继续展开后看到IPv4，那么我们可以知道这个conversation是从哪里来的。再次展开可以看到这个conversation的端口，本示例中，端口为1433到49428 。在这里需要额外讲解一下，当客户端程序创建连接到SQL Server时会使用哪些端口呢？客户端会向操作系统申请并使用一个动态端口并向SQL Server发送连接请求。如果在连接时使用的是machine name，provider默认会去连接1433端口，这是一个provider的行为，改变这个行为需要修改注册表：HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\Client\&lt;Provider&gt;\tcp\DefaultPort</span></p>
<p><span style="font-size: medium;">3. 当客户端尝试创建一个连接到SQL Server，有了source port和destination port后，在这两个port中就会形成一组physical tcp连接。形成连接之后每发一个包，包的sequence值就会发生变化。请注意，只有在同一个物理连接中，sequence的变化是连续的。如果客户端和SQL Server建立了两个不同的物理连接，这两个连接中的sequence没有任何关系。</span></p>
<p><span style="font-size: medium;">4. Netmon中数据量很大，如果查看呢？</span></p>
<p><span style="font-size: medium;">比如在浏览一个比较大的Netmon时，我们发现了一个Reset&nbsp; Flag：</span></p>
<p style="padding-left: 30px;"><span style="color: #000000; font-size: medium;"><strong>21&nbsp; 3:46:20 PM 9/5/2014&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 21.8000442&nbsp;&nbsp; Ssms.exe&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 172.22.204.237&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 172.16.221.38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TCP&nbsp;&nbsp;&nbsp;&nbsp; TCP: [Bad CheckSum]<span style="background-color: #ffff00;">Flags=...A.R..,</span> SrcPort=49428, DstPort=1433, PayloadLen=0,</strong></span><br /><span style="color: #000000; font-size: medium;"><strong>Seq=3636257929, Ack=707503184, Win=0&nbsp;&nbsp;&nbsp;&nbsp; {TCP:2,IPv4:1}</strong></span></p>
<p><span style="font-size: medium;">就可以从这个Frame的详细信息入手。从详细信息中可以找到它的source port是49428。此时我们可以就通过添加 filter <strong>Tcp.port==49428</strong> 来过滤出这个Reset的conversation。</span></p>
<p><span style="font-size: medium;">另外一种过滤方法是直接在右键单击Frame后弹出的菜单中选择Find Conversation， 但这种方法有可能会造成丢包，因此还是推荐使用第一种方法。</span></p>
<p><span style="font-size: medium;">找到了port就几乎相当于找到了出问题的连接。当然，对于不同时间点，同样的port有可能会是两个不同的连接，因为上一个连接关掉后，下一个连接有可能重用这个port。按照port过滤后，从reset 开始顺序往前看。</span></p>
<p><span style="font-size: medium;">5. 在Netmon中我们还可以看到一些protocol是TDS的Frame。TDS的好处是在查看Frame Details时，可以看到更多的信息。例如我们查看一个TDS:SQLBatch的TDS Frame Detail，可以看到SQL的statement：</span></p>
<p style="padding-left: 30px;"><span style="font-size: medium;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4186.2.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4186.2.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4186.2.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4186.2.jpg" alt="" border="0" /></a></span></p>
<p><br /><span style="font-size: medium;">对于当SQL Server使用的端口不是默认的1433时，如何显示TDS frames，可以参考下面这篇博文：<a href="https://blogs.msdn.com/b/sqlblog/archive/2010/06/30/how-to-fix-tds-parser-to-display-tds-frames-when-sqlserver-is-listening-on-port-other-than-default-1433.aspx">How to enable TDS parser to display TDS frames when SQLServer is listening on port other than default 1433</a></span></p>
<p><span style="font-size: medium;">6. 除了在4中介绍的通过port进行过滤，最常用的filter还有</span><br /><span style="font-size: medium;"><strong><span style="color: #000000;">ipv4.address==&lt;xxx.xx.xx.xx&gt;</span></strong></span></p>
<p><span style="font-size: medium;">除直接在filter中写入之外还有一种添加filter的方法，以过滤出所有flag是reset的frames为例来说明：那么我可以在某个reset frame的details中找到这个flag，在右键单击弹出的菜单中选择Add Selected</span><br /><span style="font-size: medium;">Value to Display filter：</span></p>
<p style="padding-left: 30px;"><span style="font-size: medium;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/5875.3.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/5875.3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/5875.3.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/400x400/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/5875.3.png" alt="" border="0" /></a></span></p>
<p>&nbsp;<br /><span style="font-size: medium;">7. 一个SQL Server的包会在网络传输过程中会经过以下几层：</span></p>
<p style="padding-left: 30px;"><span style="font-size: medium;"><strong>NIC（网卡物理设备）&mdash;NDIS（网卡驱动）&mdash;TCPIP （操作系统）&mdash;afd（操作系统后台线程，每一个tcp port上都会有一个afd）&mdash;SQL Server&mdash;for authentication（调用 sspi&mdash;lssas&mdash;DC）</strong></span></p>
<p><span style="font-size: medium;">Netmon所抓取的数据是在网卡驱动上面和TCPIP 下面的。所以Netmon所抓到的包是不能作为网卡真正发出去的包的，需要比较发出去的包和客户端收到的包来判断网卡或路由等是否进行了切包。</span></p>
<p><span style="font-size: medium;">8. 在chimney开启时，抓到的包的信息有可能是不全的，如果在查看时发现包的行为很奇怪，怀疑丢包，那么一定要请客户关闭chimney（以管理员运行CMD并且执行命令：netsh interface tcp set global chimney=disabled）后重新收集Netmon。</span></p>
<p>&nbsp;</p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 接下来，我们就来讨论一下今天的案例。当具备了以上Netmon的知识和技巧后，在处理这个案例中所收到的Netmon数据就非常有针对性了。将客户端的Netmon数据按照端口号filter后，可以很清楚的看到，客户端一直面对着重传的问题。16是12的重传，17也是12的重传，甚至18，19，20：</span></p>
<p style="padding-left: 30px;"><span style="font-size: medium;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/3581.4.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/3581.4.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/3581.4.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/3581.4.png" alt="" border="0" /></a></span></p>
<p><span style="font-size: medium;">那么我们来看一下12的详细信息：</span></p>
<p style="padding-left: 30px;"><span style="font-size: medium;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/2477.5.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/2477.5.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/2477.5.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/2477.5.png" alt="" border="0" /></a></span></p>
<p><span style="font-size: medium;">可以看到这个包的长度是4096。那么16呢？查看16的详细信息时我们发现，16的长度变成了1460：</span></p>
<p style="padding-left: 30px;"><span style="font-size: medium;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/0246.6.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/0246.6.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/0246.6.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/0246.6.png" alt="" border="0" /></a></span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在重传时包的长度变小说明，由于之前大包无法传递，传递的包的大小被自动调小了。继续查看17，18，19和20会发现这几个包的长度都是1460。很明显，这是一个大包发不过去导致重传的问题。</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 那么现在问题来了，为什么第一次大包发不过去，之后以小包重传也不成功呢？</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 查看server端Netmon后会发现，这是由于传输4096的包被切成1460+1460+1172后，server端只收到了最后一个包。接下来，由于sequence断了，server端会认为这是一个不合法的包，因为中间的信息缺失了。之后这个连接就在server端直接被block了（所以我们收到的错误信息是&ldquo;connection forcibly close by the remote server</span><br /><span style="font-size: medium;">&rdquo;），因此后续re-transmit的1460的包server再也没有接收过（后续重传全都失败了）。</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最终问题的解决办法是关闭网卡上的两个选项：Jumbo Packet和Large Send Offload（LSO）。</span></p>
<p style="padding-left: 30px;"><span style="font-size: medium;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8625.7.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8625.7.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8625.7.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/400x400/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8625.7.jpg" alt="" border="0" /></a></span></p>
<p style="padding-left: 30px;"><span style="font-size: medium;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4064.8.jpg" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4064.8.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4064.8.jpg" original-url="https://blogs.msdn.com/resized-image.ashx/__size/400x400/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4064.8.jpg" alt="" border="0" /></a></span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 开启Jumbo Packet表示支持大包，关闭则表示从NIC发出的包采用标准大小1500。</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果LSO是开启的，切包会由网卡驱动（NDIS）完成。如果LSO关闭，切包会由操作系统（TCP Stack）完成，切成多大由Jombo Packet的设置来决定。我们通常不建议由网卡来切包，因为网卡切包与网络环境有关，可能会导致包的大小不固定，建议还是由操作系统来进行切包。将这两个选项关闭后，传输包的大小均为标准大小1500，就解决了这个大包被切，重传失败的问题。</span></p>
<p><span style="font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这就是今天的分享，更多SQL Server案例学习请持续关注本博客的更新。</span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Windows Azure SQL 数据库介绍系列 (4)</title>
      <link>https://docs.microsoft.com/archive/blogs/apgcdsd/windows-azure-sql-4</link>
      <pubDate>Mon, 13 Apr 2015 00:30:00 GMT</pubDate>
      <dc:creator><![CDATA[APGC DSD Team]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/apgcdsd/2015/04/13/windows-azure-sql-4/</guid>
      <description><![CDATA[本文是Windows Azure SQL...]]></description>
      <content:encoded><![CDATA[<p class="Default"><span style="color: #000000; font-size: medium;">本文是Windows Azure SQL 数据库介绍系列最后一个博文，我们将给大家介绍的是SQL数据库的监控和审计功能。</span></p>
<p class="Default"><span style="color: #000000; font-size: medium;"><strong><span style="text-decoration: underline;">监控</span></strong></span></p>
<p class="Default"><span style="color: #000000; font-size: medium;">SQL数据库的性能和运行状态决定着您的业务负载是否可以流畅的读取和写入数据，并为用户提供良好的访问体验。因此作为一个管理员，您需要随时了解数据库的各项运行指标。Windows </span><span style="color: #000000; font-size: medium;">Azure为您提供了一种十分便利的监控与管理方式，您只需通过Windows Azure 管理门户，即可直观的通过图表看到这些信息。</span></p>
<p><span style="color: #000000; font-size: medium;">通过Windows Azure管理门户-&gt; </span><span style="color: #000000; font-size: medium;">SQL 数据库，在列表中选择所需的监控的数据库，点击&ldquo;监视器 </span><span style="color: #000000; font-size: medium;">(Monitor)&rdquo;，您可以了解该Windows Azure SQL数据库的概览信息，以及当前各项指标。除了默认显示的指标外，您还可以通过底下的菜单（Add </span><span style="color: #000000; font-size: medium;">Metrics）来添加更多监控指标，另外您也可以通过添加规定 (Add Rule)来制定警告阀值，一旦有警告将可以通过邮件通知发给管理员。</span></p>
<p><span style="color: #000000; font-size: medium;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8311.1.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8311.1.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/8311.1.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/8311.1.png" alt="" border="0" /></a></span></p>
<p><span style="color: #000000; font-size: medium;">SQL数据库同时也提供了丰富的DMVs和系统表可以用来监控数据库的各项情况诸如连接和性能问题。例如如下DMVs和系统表就非常有用：</span></p>
<ul>
<li><span style="color: #000000; font-size: medium;">sys.dm_exec_connections</span></li>
<li><span style="color: #000000; font-size: medium;">sys.dm_exec_sessions</span></li>
<li><span style="color: #000000; font-size: medium;">sys.dm_exec_query_stats</span></li>
<li><span style="color: #000000; font-size: medium;">sys.dm_tran_locks</span></li>
<li><span style="color: #000000; font-size: medium;">sys.dm_db_resource_stats</span></li>
<li><span style="color: #000000; font-size: medium;">sys.resource_stats</span></li>
<li><span style="color: #000000; font-size: medium;">sys.bandwidth_usage</span></li>
<li><span style="color: #000000; font-size: medium;">sys.event_log</span></li>
<li><span style="color: #000000; font-size: medium;">sys.database_connection_stats</span></li>
<li><span style="color: #000000; font-size: medium;">sys.database_usage</span></li>
</ul>
<p><span style="color: #000000; font-size: medium;">更多信息：</span><br /><br /><span style="color: #000000; font-size: medium;">Azure SQL Database Performance Guidance</span></p>
<p><span style="color: #000000; font-size: medium;"><a href="https://msdn.microsoft.com/en-us/library/azure/dn369873.aspx"><span style="color: #000000;">https://msdn.microsoft.com/en-us/library/azure/dn369873.aspx</span></a></span></p>
<p><span style="color: #000000; font-size: medium;">Monitoring Azure SQL Database Using Dynamic </span><span style="color: #000000; font-size: medium;">Management Views</span></p>
<p><span style="color: #000000; font-size: medium;"><a href="https://msdn.microsoft.com/library/azure/ff394114.aspx?amp;clcid=0x804"><span style="color: #000000;">https://msdn.microsoft.com/library/azure/ff394114.aspx?amp;clcid=0x804</span></a></span></p>
<p><span style="color: #000000; font-size: medium;"><strong><span style="text-decoration: underline;">审计</span></strong><strong></strong></span></p>
<p><span style="color: #000000; font-size: medium;">审计功能能帮助您维护公司的安全条例，了解数据库中的活动和及时发现安全问题。<strong></strong></span></p>
<p><span style="color: #000000; font-size: medium;">可以审计的事件有如下：</span></p>
<ul>
<li><span style="color: #000000; font-size: medium;">数据访问</span></li>
<li><span style="color: #000000; font-size: medium;">Schema更改(DDL)</span></li>
<li><span style="color: #000000; font-size: medium;">数据更改(DML)</span></li>
<li><span style="color: #000000; font-size: medium;">帐户, 角色和权限(DCL)</span></li>
<li><span style="color: #000000; font-size: medium;">安全例外</span></li>
</ul>
<p><span style="color: #000000; font-size: medium;">您可以用Windows Azure管理门户来非常快速和便捷的设置审计选项（如下图）。<strong></strong></span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4150.2.png" original-url="https://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4150.2.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/01/42/89/4150.2.png" original-url="https://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-01-42-89/4150.2.png" alt="" border="0" /></a></p>
<p><span style="color: #000000; font-size: medium;">更多信息：</span><br /><br /><span style="color: #000000; font-size: medium;"><a href="https://azure.microsoft.com/en-us/documentation/articles/sql-database-auditing-get-started/"><span style="color: #000000;">https://azure.microsoft.com/en-us/documentation/articles/sql-database-auditing-get-started/</span></a></span></p>
<p><span style="color: #000000; font-size: medium;"><a href="https://azure.microsoft.com/blog/2014/08/25/a-boost-in-security-for-azure-sql-database-auditing/"><span style="color: #000000;">https://azure.microsoft.com/blog/2014/08/25/a-boost-in-security-for-azure-sql-database-auditing/</span></a></span></p>
<p><span style="color: #000000; font-size: medium;">这就是今天的分享，更多SQL Server，大数据和微软云介绍请持续关注本博客。</span><br /><span style="color: #000000; font-size: medium;">接下来我们会陆续发布SQL Server的各种连接和性能的精彩案例讲解。敬请期待。</span></p>]]></content:encoded>
    </item>
  </channel>
</rss>