﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-Archangelsy-文章分类-数据库</title><link>http://www.blogjava.net/Archangelsy/category/20559.html</link><description>LSY</description><language>zh-cn</language><lastBuildDate>Sat, 11 Aug 2007 12:43:31 GMT</lastBuildDate><pubDate>Sat, 11 Aug 2007 12:43:31 GMT</pubDate><ttl>60</ttl><item><title>vc ODBC</title><link>http://www.blogjava.net/Archangelsy/articles/136060.html</link><dc:creator>archangel</dc:creator><author>archangel</author><pubDate>Sat, 11 Aug 2007 10:57:00 GMT</pubDate><guid>http://www.blogjava.net/Archangelsy/articles/136060.html</guid><wfw:comment>http://www.blogjava.net/Archangelsy/comments/136060.html</wfw:comment><comments>http://www.blogjava.net/Archangelsy/articles/136060.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Archangelsy/comments/commentRss/136060.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Archangelsy/services/trackbacks/136060.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: VC中为普通程序添加ODBC应用												摘要：本文通过用VC++6.0实现一个程序实例来介绍如何在一个普通的无数据库关联的应用程序中添加ODBC应用，使应用程序能在原有的功能基础上增加对数据库的操作。　　关键字：VC++ 、ODBC、数据库 　　一、 引言　　数据库属于最流行的应用程序之一，几乎每个商业部门都使用数据库来记录、管理各种各样的数据。在VC下我们可以在创...&nbsp;&nbsp;<a href='http://www.blogjava.net/Archangelsy/articles/136060.html'>阅读全文</a><img src ="http://www.blogjava.net/Archangelsy/aggbug/136060.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Archangelsy/" target="_blank">archangel</a> 2007-08-11 18:57 <a href="http://www.blogjava.net/Archangelsy/articles/136060.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC中为普通程序添加ODBC应用</title><link>http://www.blogjava.net/Archangelsy/articles/135659.html</link><dc:creator>archangel</dc:creator><author>archangel</author><pubDate>Thu, 09 Aug 2007 15:17:00 GMT</pubDate><guid>http://www.blogjava.net/Archangelsy/articles/135659.html</guid><wfw:comment>http://www.blogjava.net/Archangelsy/comments/135659.html</wfw:comment><comments>http://www.blogjava.net/Archangelsy/articles/135659.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Archangelsy/comments/commentRss/135659.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Archangelsy/services/trackbacks/135659.html</trackback:ping><description><![CDATA[摘要：本文通过用VC++6.0实现一个程序实例来介绍如何在一个普通的无数据库关联的应用程序中添加ODBC应用，使应用程序能在原有的功能基础上增加对数据库的操作。<br /><br />　　关键字：VC++ 、ODBC、数据库 <br /><br />　　一、 引言<br /><br />　　数据库属于最流行的应用程序之一，几乎每个商业部门都使用数据库来记录、管理各种各样的数据。在VC下我们可以在创建工程时选择数据库支持，并选定数据源和相关的表，并选择CRecordView作为我们这个程序的基类，这样做可以毫不费力的将应用程序和数据库建立了关联，而几乎不用编什么代码，但这样做的前提是在新建工程时已明确知道用到哪个数据库，并且有相关的数据库。事实上我们往往有许多已做好的应用程序和类，其功能除了未和数据源建立关联外以基本满足要求，我们只要在其基础上添加ODBC接口，使之与数据库建立关联即可，这样做避免了与数据库无关部分代码的重新编写所造成的重复性操作，大大提高了代码的重用性和利用率。所以在普通程序上通过添加ODBC应用而与数据库建立关联的方法是完全行之有效的。<br /><br />　　二、 ODBC技术<br /><br />　　ODBC（Open Database Conectivity 开放式数据库互联）技术，作为Microsoft公司对数据库进行访问的标准应用程序接口(API)和Windows开放式服务体系结构OSA的一个重要组成部分已广为众多的Windows程序员所熟悉、认可。ODBC的工作依赖于数据库制造商提供的驱动程序，使用ODBC API的时候，Windows的ODBC管理程序，把数据库访问的请求传递给正确的驱动程序，驱动程序再使用SQL语句指示DBMS完成数据库访问工作，因此，ODBC的存在为我们开发应用数据库程序提供了非常强大的能力和灵活性。 <br /><br />　　三、 程序示例<br /><br />　　(一)打开Visual C++，在"File"菜单上点选"New…"，然后在弹出的"New"对话框中选定"MFC AppWizard(exe)"类的项目，"Project name"为Normal，按下OK键，下一Step 1屏幕中选"Single document"单文档支持，用到后面的选项除在最后一步选择"CFormView"作为本工程视类的基类外均为确省值，此时即可按下Finish键，结果系统将生成一个新的项目Normal。<br /><br />　　我们就将此工程当做原有的工程，接下来我们便在此工程基础上对其添加ODBC应用，使该工程能同数据源建立关联，能对数据库中的数据进行操作和管理。<br /><br />　　(二)打开"控制面板"上的"ODBC (32bits)"，对数据源进行注册。为了使ODBC能与数据库一起工作，就必须把数据库注册到ODBC驱动程序管理器，这项工作可以通过定义一个DSN或数据源名字来完成。在弹出的"ODBC数据源管理器"中选择"User DSN"属性页，点击"Add…"按钮。选择"Microsoft Access Driver(*.mdb)"作为数据源的驱动器，点击"完成"按钮。在弹出的"ODBC Microsoft Access 97 Setup"对话框中在"Data Source Name:"栏添入RP97,"Description:"栏只起注释说明的作用，可以不填，然后点击"Select…"按钮，选择所要注册的数据源，然后点击"OK"就完成了对数据源的注册，到这一步，本机上的任意程序只要通过ODBC接口和数据源名"RP97"就能完成对数据库的访问了。<br /><br />　　(三)在VC的"Workspace"活动窗口中选择"FileView"属性页，打开标准框架头文件"StdAfx.h",并在最后一个#include后面添加对"afxdb.h"的引用：#include <afxdb.h></afxdb.h><br /><br />　　(四) 在"Workspace"活动窗口中选择"ClassView"属性页，在"Normal Classes"上右键，选"New Class…",在弹出的"New Class"对话框的"Base Class"栏选择"CRecordSet"做为新添加的类的基类，在"Name"栏填写类名"CODBCSet",点击"OK"，在随后弹出的对话框的"ODBC"栏选择刚注册的"RP97"数据源，点击"OK"后选择该数据库的一个表，点击"OK"在"ClassView"里就多了一个以CRecordSet为基类的新类"CODBCSet"。下面三个函数完成了数据库各级元素的绑定工作：<br /><br />CString CODBCSet::GetDefaultConnect()<br />{<br />　return _T("ODBC;DSN=RP97");<br />}<br /><br />CString CODBCSet::GetDefaultSQL()<br />{<br />　return _T("[单据表]");<br />}<br /><br />void CODBCSet::DoFieldExchange(CFieldExchange* pFX)<br />{<br />　//{{AFX_FIELD_MAP(CODBCSet)<br />　pFX-&gt;SetFieldType(CFieldExchange::outputColumn);<br />　RFX_Text(pFX, _T("[单据ID]"), m_column1);<br />　RFX_Text(pFX, _T("[单据名称]"), m_column2);<br />　RFX_Text(pFX, _T("[报帐人]"), m_column3);<br />　//}}AFX_FIELD_MAP<br />} <br /><br />　　(五)按同样的方法再添加一个基于"generic CWnd"的新类"CConnectDB"。在该类的源文件里添加对"ODBCSet.h"的引用：#include "ODBCSet.h"。在该类的头文件的"class CconnectDB"前添加class CODBCSet；并在该类里添加公有型成员变量和函数：<br /><br />CDatabase m_dbData;<br />CODBCSet* m_pSet;<br />void CConnectDB::Initial()<br />{<br />　//打开数据源RP97<br />　CString os=_T("odbc; dsn=RP97");<br />　m_dbData.Open(NULL,FALSE,FALSE,0);<br />　m_pSet=new CODBCSet(&amp;m_dbData);<br />　//通过SQL结构化查询语言打开RP97里的单据表<br />　CString sql="SELECT * FROM 单据表";<br />　m_pSet-&gt;Open(AFX_DB_USE_DEFAULT_TYPE,sql);<br />}<br /><br /><br />　　(六)在Form上添加一个"测试"按钮及其响应函数OnTest()：<br /><br />void CNormalView::OnTest() <br />{<br />　CConnectDB connectDB;<br />　//执行完Initial()后m_pSet指针才不为空，方可安全使用。<br />　connectDB.Initial();<br />　if(connectDB.m_pSet==NULL)<br />　　return;<br />　connectDB.m_pSet-&gt;MoveFirst();<br />　CString str=connectDB.m_pSet-&gt;m_column3;<br />　AfxMessageBox(str);<br />} <br /><br />　　最后在该文件开始处添加两个引用：<br /><br />#include "ConnectDB.h"<br />#include "ODBCSet.h" <br /><br />　　四、 运行与测试<br /><br />　　编译运行程序，点击"测试"按钮，就会将"RP97"数据库的"单据表"的第一条记录的"报帐人"字段所在的内容通过对话框弹出来。<br /><br />　　小结：<br /><br />　　本程序的关键在于对数据库指针m_pSet的获取，当类CConnectDB 的成员函数Initial()被执行完时，m_pSet就已被获取到了，而在此之前该指针是空的，是不能使用的，所以在实际应用中必须保证在使用m_pSet之前调用过函数Initial()。当m_pSet被获取到之后，就可以想其他ODBC应用程序一样使用CrecordSet类里的各种函数对数据库进行各种需要的操作和管理了。<img src ="http://www.blogjava.net/Archangelsy/aggbug/135659.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Archangelsy/" target="_blank">archangel</a> 2007-08-09 23:17 <a href="http://www.blogjava.net/Archangelsy/articles/135659.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle9i 转化时区</title><link>http://www.blogjava.net/Archangelsy/articles/113173.html</link><dc:creator>archangel</dc:creator><author>archangel</author><pubDate>Tue, 24 Apr 2007 06:26:00 GMT</pubDate><guid>http://www.blogjava.net/Archangelsy/articles/113173.html</guid><wfw:comment>http://www.blogjava.net/Archangelsy/comments/113173.html</wfw:comment><comments>http://www.blogjava.net/Archangelsy/articles/113173.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Archangelsy/comments/commentRss/113173.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Archangelsy/services/trackbacks/113173.html</trackback:ping><description><![CDATA[
		<span style="FONT-SIZE: 14px">在Oracle9i之前，虽然有一个NEW_TIME函数可以改变DATE的时间戳部分，但是还没有专门用来存储时区信息的数据类型。在Oracle9i中，我们可以使用DBTIMEZONE伪字段查询数据库的时区，使用SESSIONTIMEZONE伪字段查询会话的时区。 
<p></p><p style="TEXT-INDENT: 2em">但是，对于大多数数据库，这些值都是-07:00之类的偏移值，因此对于NEW_TIME函数是没有用的。Oracle9i有关NEW_TIME的文档建议使用FROM_TZ来替代，但是这可能会产生误导。FROM_TZ只将一个时区应用到一个时间戳上；它并不能把一个时区转换成另外一个时区。 </p><p style="TEXT-INDENT: 2em">其实有一个比较好的方法（从文档中得到这个方法可能有点难）。首先，为了完成这个工作，在正确的时区内需要一个TIMESTAMP WITH ZONE数据类型。然后，如果你将关键字AT TIME ZONE应用到那个值，它就会自动地调整为新的时区和日期。 </p><p style="TEXT-INDENT: 2em"> </p><center><ccid_nobr></ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code></ccid_code>　　

　　select (timestamp '2003-04-06 01:59:59' at time zone 'PDT') 

    at time zone 'GMT'

　　from dual;

　　

　　06-APR-03 08.59.59.00000000 AM GMT</pre></td></tr></tbody></table></center>　　 
<p style="TEXT-INDENT: 2em">这个语句将为太平洋白天时间（即其切换到PST之前的时刻）构造一个TIMESTAMP WITH TIME ZONE然后再将其转换到GMT。AT TIME ZONE关键字也接受默认的偏移值语法： </p><p style="TEXT-INDENT: 2em"> </p><center><ccid_nobr></ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code></ccid_code>　　

　　select (timestamp '2003-04-06 02:00:00' 

    at time zone '-07:00') at time zone

　　'00:00' from dual;

　　

　　06-APR-03 09.00.00.000000000 AM +00:00

　</pre></td></tr></tbody></table></center>　 
<p style="TEXT-INDENT: 2em">你还可以使用伪字段来自动调整当前会话的时区： </p><p style="TEXT-INDENT: 2em"> </p><center><ccid_nobr></ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code></ccid_code>　　

　　selectcurrent_timestamp at time zone dbtimezone from dual;</pre></td></tr></tbody></table></center>　　 
<p style="TEXT-INDENT: 2em">上面的表达式返回一个当前会话的本地时间（数据类型为时区），重新调整数据库的时区，调整后的时区将与SYSTIMESTAMP的结果相等。 </p><p style="TEXT-INDENT: 2em">有了以上的这些信息，就可以构造一个比较好的NEW_TIME函数： </p><p style="TEXT-INDENT: 2em"> </p><center><ccid_nobr></ccid_nobr><table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="#000000" border="1"><tbody><tr><td class="code" style="FONT-SIZE: 9pt" bgcolor="#e6e6e6"><pre><ccid_code></ccid_code>　　

　　create or replace function my_new_time

　　(

　　　　p_dwtz timestamp with time zone,

　　　　p_tz varchar2

　　) return date

　　is

　　begin

　　　　return cast(p_dwtz at time zone p_tz as date);

　　end my_new_time;

　　/

　　show errors;

　　

　　select my_new_time(sysdate,'+08:00') from dual;</pre></td></tr></tbody></table></center>　　 
<p style="TEXT-INDENT: 2em">即使第一个参数被标记为一个timestamp with time zone，你依然可以传入一个TIMESTAMP和DATE，这样由于Oracle的自动转型操作，得到的时间将是会话在本地时区的当前时间。这个函数接受包括偏移值在内的任何可以被TIMESTAMP识别的时区，然后将接受的时区调整为正确的值。</p><p></p></span>
<img src ="http://www.blogjava.net/Archangelsy/aggbug/113173.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Archangelsy/" target="_blank">archangel</a> 2007-04-24 14:26 <a href="http://www.blogjava.net/Archangelsy/articles/113173.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>select返回记录的顺序（转）</title><link>http://www.blogjava.net/Archangelsy/articles/110450.html</link><dc:creator>archangel</dc:creator><author>archangel</author><pubDate>Fri, 13 Apr 2007 06:45:00 GMT</pubDate><guid>http://www.blogjava.net/Archangelsy/articles/110450.html</guid><wfw:comment>http://www.blogjava.net/Archangelsy/comments/110450.html</wfw:comment><comments>http://www.blogjava.net/Archangelsy/articles/110450.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Archangelsy/comments/commentRss/110450.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Archangelsy/services/trackbacks/110450.html</trackback:ping><description><![CDATA[<font face=宋体>关键词：select，顺序，优化，备份，扫描，索引 <br>文章摘要： <br>&nbsp;&nbsp;&nbsp;当我们执行了select语句，select返回的记录的顺序对我们编程方式有较大影响，对数据库记录备份清除以及sql性能优化都有很大的关系。因此有必要明确select返回记录的顺序。本文按数据库分类讨论oracle/sybase/sql&nbsp;server返回记录的顺序，从原理探讨三种数据库各自的特点，并着重探讨了这些差异对数据查询及记录备份的影响。 <br>缩略语： <br>IAM：index&nbsp;allocation&nbsp;map <br>PFS：page&nbsp;free&nbsp;space <br>1.简介 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当我们执行了select语句，select返回的记录的顺序对我们编程方式有较大影响，对数据库记录备份清除以及sql性能优化都有很大的关系。因此有必要明确select返回记录的顺序。 <br>select返回记录的顺序与数据库类型有很大关系，因此以下按数据库类型分别讨论。本文主要讨论了oracle/sybase/sql&nbsp;server返回记录的顺序，从原理探讨三种数据库各自的特点，并着重探讨了这些差异对数据查询及记录备份的影响。 <br>2.&nbsp;oracle <br>以下假设数据库查询优化方式均为基于rule的方式，ORACLE&nbsp;采用两种访问表中记录的方式： <br>　　a.&nbsp;全表扫描&nbsp;(Full&nbsp;Table&nbsp;Scan) <br>　　全表扫描就是顺序地访问表中每条记录.&nbsp;ORACLE采用一次读入多个数据块(database&nbsp;block)的方式优化全表扫描。 <br>　　b.&nbsp;通过ROWID访问表 <br>你可以采用基于ROWID的访问方式情况，提高访问表的效率，ROWID包含了表中记录的物理位置信息。ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系。通常索引提供了快速访问ROWID的方法，因此那些基于索引列的查询就可以得到性能上的提高。通常表现为按索引扫描。(Index&nbsp;Scan) <br>2.1全表扫描 <br>如果select语句不能使用索引，则Oracle按全表扫描方式读取数据块，对于返回的结果集，oracle按rowid的大小顺序来返回记录。因此&nbsp;select&nbsp;*&nbsp;from&nbsp;mytable&nbsp;与&nbsp;select&nbsp;*&nbsp;from&nbsp;mytable&nbsp;order&nbsp;by&nbsp;rowid效果是一样的 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可以通过select&nbsp;rowid&nbsp;from&nbsp;table得到rowid伪列，数据类型为ROWID类型。使用查询语句返回的是ROWID的扩展格式（Extended&nbsp;Rowid）。扩展格式的ROWID由18个字符组成。这18个字符可以按照OOOOOO.FFF.BBBBBB.SSS的格式分为4组。分别代表数据对象编号（Data&nbsp;Object&nbsp;Number）,数据文件编号（Datafile&nbsp;Number），数据块编号（Data&nbsp;Block&nbsp;Number）,记录或记录片断的块内行号。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;必须说明的是，并不是后插入记录的rowid就越大，有可能后插入的记录rowid还要小。下面给出两个论点加以证明： <br>1．后插入的记录块内行号可能大，也可能小 <br>根据我们的试验，假设现在表中有三条记录假设文件号相同，按块号，行号排列如下： <br>108&nbsp;0 <br>108&nbsp;1 <br>108&nbsp;2 <br>删除中间一条记录后，得到 <br>108&nbsp;0 <br>108&nbsp;2 <br>再增加一条记录，可能会得到 <br>108&nbsp;0 <br>108&nbsp;1&nbsp;&nbsp;&lt;---新增加的记录 <br>108&nbsp;2 <br>也可能是 <br>108&nbsp;0 <br>108&nbsp;2 <br>108&nbsp;3&nbsp;&nbsp;&lt;---新增加的记录 <br>两种情况均有可能出现，取决于oracle块内的分配算法。关于该情况的更深入的分析可以参见文献2。 <br>2．后插入的记录的块号有可能大，有可能小 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;插入记录的块号并不是线性增加的，而是受FreeList控制。有关FreeList的理论和算法可以参见文献1。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>因此对于全表扫描可以得出以下结论： <br>1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在oracle中&nbsp;select&nbsp;*&nbsp;from&nbsp;mytable不能保证返回的记录顺序是按插入的先后顺序，而是按rowid顺序。 <br>rowid的顺序与记录行存储的&#8220;物理序&#8221;一致。在没有索引情况下，select作全表扫描，是按&#8220;物理序&#8221;，此时select&nbsp;返回记录按&#8220;物理序&#8221;最快。 <br>2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于已经插入的记录其ROWID不会发生变化。 <br>如果全表扫描方式下，直接使用rownum作为选择条件，根据结论1，两次得到的记录可能是不一样的。如果sql有时间条件或其他条件作为sql语句辅助的筛选（排出当前插入的值），那么再用rownum作为选择条件，则返回的记录及记录的顺序均是一样的。 <br>结论2的特性可用于某些日志表的清除-备份机制中。对于某些日志表为了提高insert性能，可能没有索引，并且在存储过程中对这些日志表进行清除和备份。利用insert&nbsp;into&nbsp;select&nbsp;先将部分记录选入到备份表中，再用delete语句删除日志表中的记录。通过rownum来控制操作的行数，避免回滚段问题，通过时间条件来实施结论2，保证记录一致。 <br>2.2按索引扫描 <br>对于一段范围的按索引选择，在oracle内部表现为索引叶节点的扫描，索引叶节点通常已经排序并且叶节点之间存在指针，便于扫描。由于此时select按索引扫描表，因此返回的记录就按&#8220;索引序&#8221;排列。 <br>利用上述特征，对于按索引扫描可以有以下的应用方式： <br>1．通过索引可以使返回记录事先排序。 <br>在oracle中使用索引就可以使返回的记录得到排序，而无需再使用order&nbsp;by。对于不同的排序方式可以用不同的索引完成，通过hint/*+*/指示可以控制索引按不同的扫描方式工作，从而达到不同的效果。如/*+INDEX(TABLE&nbsp;INDEX_NAME)*/或/*+INDEX_DESC(TABLE&nbsp;INDEX_NAME)*/指示按索引升序扫描或按索引降序扫描，从而实现返回的记录按字段的升序排列或按字段的降序排列。 <br>例如对于表T(a&nbsp;int,b&nbsp;int)在a上有索引index_a，b上有索引b <br>则select&nbsp;*&nbsp;from&nbsp;t得到的记录 <br>&nbsp; <br>AB <br>1943 <br>211 <br>310 <br>58 <br>112 <br><br>select&nbsp;/*+INDEX(T&nbsp;INDEX_A)*/*&nbsp;from&nbsp;t&nbsp;where&nbsp;a&gt;0&nbsp;或者 <br>select&nbsp;*&nbsp;from&nbsp;t&nbsp;where&nbsp;a&gt;0&nbsp;order&nbsp;by&nbsp;a <br>AB <br>310 <br>58 <br>112 <br>1943 <br>211 <br><br>从执行计划来看，按索引扫描和按索引ROWID方式访问。 <br>select&nbsp;/*+INDEX_DESC(T&nbsp;INDEX_B)*/*&nbsp;from&nbsp;t&nbsp;where&nbsp;b&gt;0&nbsp;或者 <br>select&nbsp;*&nbsp;from&nbsp;t&nbsp;where&nbsp;b&gt;0&nbsp;order&nbsp;by&nbsp;b <br>AB <br>211 <br>112 <br>58 <br>310 <br>1943</font><br><font face=宋体>从执行计划来看，按索引扫描和按索引ROWID方式访问。 <br>2．通过以时间、流水号等字段为索引字段，可以使记录实现按插入的顺序返回 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;同样利用上述特性，来说明2.1中的备份问题。当日志表有索引时，选择限定扫描范围的索引字段，使之保证后插入的记录是在结果集后面的，如时间或流水号等，该顺序就保证了按rownum控制行数时insert和delete操作的记录是完全一致的，同时基于索引的扫描保证了sql的性能。 <br>3.sybase <br>不管你的select&nbsp;语句中是否在where后面使用了索引，sybase均可能基于代价对索引的使用进行调整。即使没有where语句也有可能使用索引，即使有where语句也有可能不用索引。当然，如果表本身就没有创建任何索引就肯定不会使用到索引。 <br>3.1没有索引的表 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;没有索引的表在称为堆表。堆表在sysindexes表中有一条对应的记录，其indid=0。first字段表示堆表的首页，root表示堆表的尾页。堆表中所有的数据页形成从sysindex.first&nbsp;&lt;-&gt;&nbsp;sysindex.root的双向链表。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于插入记录，插入到堆表中的所有数据会加到该表的尾部。sybase&nbsp;利用sysindex表的indid（=0）和root值，找出该表的最后一个数据页。如果在该页上有空间，在数据的尾部插入新的记录行。如果最后一页上没有可获得的空间时，如果在该扩展单元的下一页有可获得的空间，这是用它；如果最后一页已经是扩展单元的最后一页，则开始使用一个新的扩展单元，对于新加入的页总是会链到链表的尾部，同时更新sysindex.root的值。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于记录删除，当删除一条记录时，页内紧随被删除记录后的记录向该页前部移动，所有未使用的空间相邻地保留在页的底部。当一页中所有行均被删除，这一页就会脱离该堆表的数据链。 <br>&nbsp;&nbsp;&nbsp;&nbsp;对于更新，堆表按下面的原则：&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果行的长度没有变化,就在原来的行上直接更新，并且没有页内数据的移动。&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果行的长度变化，并且页的空闲空间足够。行还是在页上的相同位置，但是其它行将上移或下移以保持页内行的连续。&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果该页不能容纳行。在Allpages-locked堆表中，行会被删除，并且&#8220;新&#8221;行插入到最后页。Data-only-lockedthe&nbsp;堆表中，行插入到另外的页中，在原来的位置采用转向指针指到该页面，这样保证行的ID位置不变。 <br>对于扫描，按sysindex.first&nbsp;&lt;-&gt;&nbsp;sysindex.root链表方式读取数据页。 <br>对于堆表，根据上述插入、删除、更新、扫描特性，可以得到下面的结论： <br>1．对于不带任何索引的堆表，如果确保不使用update，或确保update不产生插入操作，就可以放心的使用select&nbsp;完成自然排序，此时记录按插入的先后顺序返回。 <br><br>3.2有索引的表 <br>对于sybase执行计划没有带索引的表,select返回记录的顺序和堆表扫描返回的顺序相同。 <br>对于sybase执行计划带索引的表，select&nbsp;&nbsp;按索引字段的顺序返回记录。sybase将索引组织为&nbsp;B&nbsp;树。索引内的每一页包含一个页首，页首后面跟着索引行。每个索引行都包含一个键值以及一个指向较低级页或数据行的指针。索引的每个页称为索引节点。B&nbsp;树的顶端节点称为根节点。索引的底层节点称为叶节点。每级索引中的页链接在双向链接列表中。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;对于有索引的表，得到以下结论： <br>1．以通过控制索引来控制查询方式，从而控制返回顺序。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如我们可以通过(index&nbsp;index_name)来指定对某个索引的使用，从而达到按索引index_name排序。也可以使用(index&nbsp;0)指示强制不使用索引，从而使返回的记录顺序按堆表方式。 <br>2．如何没有强制指定索引，不管你的select&nbsp;语句中是否在where后面使用了索引，sybase均可能基于代价对索引的使用进行调整。由于sybase基于代价执行计划会对索引的使用进行调整，因此不能像oracle那样利用非聚簇索引完成返回记录的自然排序，这时最好加上order&nbsp;by以保证排序的准确。 <br>3．如果需要排序的字段是聚簇索引，那么就可以放心使用该索引完成排序。这时，不论执行计划怎样，sybase均按聚簇索引字段顺序返回记录。对于聚簇索引表，在插入数据时，会引起页内部分记录（值大的记录）的移动，通过移动sybase保证了数据的物理顺序与聚簇索引顺序一致。 <br>4.Ms&nbsp;Sql&nbsp;Server <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;不管你的select&nbsp;语句中是否在where后面使用了索引，Sql&nbsp;Server均可能基于代价对索引的使用进行调整。即使没有where语句也有可能使用索引，即使有where语句也有可能不用索引。当然，如果表本身就没有创建任何索引就肯定不会使用到索引。 <br>4.1没有索引的表 <br>没有索引的表在称为堆表或堆集。堆集使用&nbsp;IAM管理扩展盘区，多个IAM形成IAM链。堆集在&nbsp;sysindexes&nbsp;内有一行，其&nbsp;indid&nbsp;=&nbsp;0。sysindexes.FirstIAM&nbsp;列指向&nbsp;IAM&nbsp;页链的&nbsp;IAM&nbsp;首页，IAM&nbsp;页链管理分配给堆集的空间。SQL&nbsp;Server&nbsp;2000&nbsp;使用&nbsp;IAM&nbsp;页在堆集中浏览。堆集内的数据页和行没有任何特定的顺序，也不链接在一起。数据页之间唯一的逻辑连接是记录在&nbsp;IAM&nbsp;页内的连接。 <br>对于插入操作，当SQL&nbsp;Server&nbsp;2000&nbsp;需要插入新行而当前页没有可用空间时，它使用&nbsp;IAM&nbsp;和&nbsp;PFS&nbsp;页查找具有足够空间容纳该行的页。SQL&nbsp;Server&nbsp;使用&nbsp;IAM&nbsp;页查找分配给对象的扩展盘区。对于每个扩展盘区，SQL&nbsp;Server&nbsp;搜索&nbsp;PFS&nbsp;页以查看是否有一页具有足够的空间容纳这一行。 <br>SQL&nbsp;Server&nbsp;只有当无法在现有的扩展盘区内快速找到一页有足够空间容纳正插入的行时，才给对象分配新的扩展盘区。SQL&nbsp;Server&nbsp;使用按比例分配算法，从文件组内的可用扩展盘区中分配扩展盘区。如果一个文件组有两个文件，其中一个的可用空间是另一个的两倍，那么每从后者分配一页，就从前者分配两页。这意味着文件组内的每个文件应该有近似的空间使用百分比。 <br>对于删除操作，在堆表中，即使删除了记录，该记录所在页不会作页内移动。 <br>对于数据更新，SQL&nbsp;Server可以采用多种方式来进行。更新可能是现场发生的，也可能是以先删除然后插入的方式进行的，还可以是通过查询处理器或存储引擎来管理更新。但是在堆表中，总是采用现场更新方式，对于更新的内容原来的页不能容纳的情况，sql&nbsp;server&nbsp;2000采用转向指针处理，保证了更新后该记录位置的不变。 <br>通过扫描&nbsp;IAM&nbsp;页可以对堆集进行表扫描或串行读，以找到容纳这个堆集的页的扩展盘区。因为&nbsp;IAM&nbsp;按扩展盘区在数据文件内存在的顺序表示它们，所以这意味着串行堆集扫描一律沿每个文件进行。 <br>根据上述堆表的插入、更新、删除、扫描原则，可以得到以下的结论： <br>1．使用&nbsp;IAM&nbsp;页设置扫描顺序意味着堆集中的行一般不按照插入的顺序返回。 <br>2．对于已经存在的记录，记录的位置（数据库号，文件号，页号，行号）不会变化。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;结论2可应用到备份-清除机制中。如果日志表是没有索引的堆表，就可以通过时间、流水号等字段排除当前插入的记录，使select和delete两次操作返回的结果集及顺序完全一致，再通过set&nbsp;rowcount来控制每次操作的记录条数，使得备份-清除操作能够安全进行。 <br>4.2有索引的表 <br>对于Sql&nbsp;Server&nbsp;执行计划没有带索引的表,select返回记录的顺序和堆表扫描返回的顺序相同。 <br>对于Sql&nbsp;Server&nbsp;执行计划带索引的表，select&nbsp;&nbsp;&nbsp;按索引字段的顺序返回记录。SQL&nbsp;Server将索引组织为&nbsp;B&nbsp;树。索引内的每一页包含一个页首，页首后面跟着索引行。每个索引行都包含一个键值以及一个指向较低级页或数据行的指针。索引的每个页称为索引节点。B&nbsp;树的顶端节点称为根节点。索引的底层节点称为叶节点。每级索引中的页链接在双向链接列表中。 <br>对于有索引的表，得到以下结论： <br>1．可以通过控制索引来控制查询方式，从而控制返回顺序。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如我们可以通过with(index(index_name))来指定对某个索引的使用，从而达到按索引index_name排序。 <br>2．如何没有强制指定索引，不管你的select&nbsp;语句中是否在where后面使用了索引，Sql&nbsp;Server均可能基于代价对索引的使用进行调整，即使没有where语句也有可能使用索引，即使有where语句也有可能不用索引。不管你的delete&nbsp;语句中是否在where后面使用了索引，Sql&nbsp;Server均可能基于代价对索引的使用进行调整，即使没有where语句也有可能使用索引，即使有where语句也有可能不用索引。带相同where语句的select&nbsp;和&nbsp;delete&nbsp;执行计划很可能不一样。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;因此select&nbsp;和&nbsp;delete&nbsp;得到的记录顺序很可能不一致，如果要选取前n条记录,那么得到的记录集尽管条数一致但内容不一致。尽管我们可以通过with(index(index_name))来强制select对索引的使用，但delete却不能够强制指定索引，因为delete涉及对索引本身的删除。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这种情况下，如果数据库的性能够好，要备份的数据不多，就不要使用set&nbsp;rowcount来控制条数。但如果确需要控制一次删除的条数，可以直接在where条件中控制更小的范围，如时间范围控制到小时，一天的数据通过24小时的循环来备份。 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;要么采用DTS作备份。 <br>3．如果需要排序的字段是聚簇索引，那么就可以放心使用该索引完成排序。这时，不论执行计划怎样，sql&nbsp;server均按聚簇索引字段顺序返回记录。</font><br><br>
<img src ="http://www.blogjava.net/Archangelsy/aggbug/110450.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Archangelsy/" target="_blank">archangel</a> 2007-04-13 14:45 <a href="http://www.blogjava.net/Archangelsy/articles/110450.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>