随笔-17  评论-0  文章-4  trackbacks-0
  2008年9月11日
運行看結果,慢慢了解
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;


public class Testone {
public static void main(String args[]){
A a=new A();
//a.test();
//SoftReference sr = new SoftReference(a);
ReferenceQueue<A> rq = new ReferenceQueue<A>();
WeakReference<A> wr = new WeakReference<A>(a, rq);
a = null;
System.out.println(wr.get());
System.out.println(rq.poll());
System.gc();
System.runFinalization();
System.out.println(wr.get());
System.out.println(rq.poll());
if (wr != null) {
a = (A)wr.get();
System.out.println("asdasdas");
a.test();
}
else{
a = new A();
System.out.println("123123");
a.test();
a = null;
wr = new WeakReference<A>(a);
}

}
}
class A{
void test(){
System.out.println("A.test()");
}
}
posted @ 2008-12-06 21:14 竹子 阅读(447) | 评论 (0)编辑 收藏

垃圾回收与强引用,软引用,弱引用,幻引用的关系(一)

Java 2 平台引入了 java.lang.ref 包,其中包括的类可以让您引用对象,而不将它们留在内存中。这些类还提供了与垃圾收集器(garbage collector)之间有限的交互。Peter Haggar 在本文中分析了 SoftReference、WeakReference 和 PhantomReference 类的功能和行为,并就这些类的使用给出了一些编程风格上的建议。
当在 Java 2 平台中首次引入 java.lang.ref 包(其中包含 SoftReference、WeakReference 和 PhantomReference 类)时,它的实用性显然被过分夸大了。它包含的类可能是有用的,但这些类具有的某些局限性会使它们显得不是很有吸引力,而且其应用程序也将特别局限于解决一类特定的问题。

垃圾收集概述
引用类的主要功能就是能够引用仍可以被垃圾收集器回收的对象。在引入引用类之前,我们只能使用强引用(strong reference)。举例来说,下面一行代码显示的就是强引用 obj:


Object obj = new Object();




obj 这个引用将引用堆中存储的一个对象。只要 obj 引用还存在,垃圾收集器就永远不会释放用来容纳该对象的存储空间。

当 obj 超出范围或被显式地指定为 null 时,垃圾收集器就认为没有对这个对象的其它引用,也就可以收集它了。然而您还需要注意一个重要的细节:仅凭对象可以被收集并不意味着垃圾收集器的一次指定运行就能够回收它。由于各种垃圾收集算法有所不同,某些算法会更频繁地分析生存期较短的对象,而不是较老、生存期较长的对象。因此,一个可供收集的对象可能永远也不会被回收。如果程序在垃圾收集器释放对象之前结束,这种情况就可能会出现。因此,概括地说,您永远无法保证可供收集的对象总是会被垃圾收集器收集。

这些信息对于您分析引用类是很重要的。由于垃圾收集有着特定的性质,所以引用类实际上可能没有您原来想像的那么有用,尽管如此,它们对于特定问题来说还是很有用的类。软引用(soft reference)、弱引用(weak reference)和虚引用(phantom reference)对象提供了三种不同的方式来在不妨碍收集的情况下引用堆对象。每种引用对象都有不同的行为,而且它们与垃圾收集器之间的交互也有所不同。此外,这几个新的引用类都表现出比典型的强引用“更弱”的引用形式。而且,内存中的一个对象可以被多个引用(可以是强引用、软引用、弱引用或虚引用)引用。在进一步往下讨论之前,让我们来看看一些术语:

强可及对象(strongly reachable):可以通过强引用访问的对象。


软可及对象(softly reachable):不是强可及对象,并且能够通过软引用访问的对象。


弱可及对象(weakly reachable):不是强可及对象也不是软可及对象,并且能够通过弱引用访问的对象。


虚可及对象(phantomly reachable):不是强可及对象、软可及对象,也不是弱可及对象,已经结束的,可以通过虚引用访问的对象。


清除:将引用对象的 referent 域设置为 null,并将引用类在堆中引用的对象声明为可结束的。
SoftReference 类
SoftReference 类的一个典型用途就是用于内存敏感的高速缓存。SoftReference 的原理是:在保持对对象的引用时保证在 JVM 报告内存不足情况之前将清除所有的软引用。关键之处在于,垃圾收集器在运行时可能会(也可能不会)释放软可及对象。对象是否被释放取决于垃圾收集器的算法以及垃圾收集器运行时可用的内存数量。 

WeakReference 类
WeakReference 类的一个典型用途就是规范化映射(canonicalized mapping)。另外,对于那些生存期相对较长而且重新创建的开销也不高的对象来说,弱引用也比较有用。关键之处在于,垃圾收集器运行时如果碰到了弱可及对象,将释放 WeakReference 引用的对象。然而,请注意,垃圾收集器可能要运行多次才能找到并释放弱可及对象。

PhantomReference 类
PhantomReference 类只能用于跟踪对被引用对象即将进行的收集。同样,它还能用于执行 pre-mortem 清除操作。PhantomReference 必须与 ReferenceQueue 类一起使用。需要 ReferenceQueue 是因为它能够充当通知机制。当垃圾收集器确定了某个对象是虚可及对象时,PhantomReference 对象就被放在它的 ReferenceQueue 上。将 PhantomReference 对象放在 ReferenceQueue 上也就是一个通知,表明 PhantomReference 对象引用的对象已经结束,可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动。  

垃圾收集器和引用交互
垃圾收集器每次运行时都可以随意地释放不再是强可及的对象占用的内存。如果垃圾收集器发现了软可及对象,就会出现下列情况:

SoftReference 对象的 referent 域被设置为 null,从而使该对象不再引用 heap 对象。


SoftReference 引用过的 heap 对象被声明为 finalizable。


当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放,SoftReference 对象就被添加到它的 ReferenceQueue(如果后者存在的话)。
如果垃圾收集器发现了弱可及对象,就会出现下列情况:

WeakReference 对象的 referent 域被设置为 null,从而使该对象不再引用 heap 对象。


WeakReference 引用过的 heap 对象被声明为 finalizable。


当 heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放时,WeakReference 对象就被添加到它的 ReferenceQueue(如果后者存在的话)。
如果垃圾收集器发现了虚可及对象,就会出现下列情况:

PhantomReference 引用过的 heap 对象被声明为 finalizable。


与软引用和弱引用有所不同,PhantomReference 在堆对象被释放之前就被添加到它的 ReferenceQueue。(请记住,所有的 PhantomReference 对象都必须用经过关联的 ReferenceQueue 来创建。)这使您能够在堆对象被回收之前采取行动。
请考虑清单 1 中的代码。

清单 1. 使用 WeakReference 及 ReferenceQueue 的示例代码
//Create a strong reference to an object
MyObject obj = new MyObject(); //1

//Create a reference queue
ReferenceQueue rq = new ReferenceQueue(); //2

//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq); //3



行 //1 创建 MyObject 对象,而行 //2 则创建 ReferenceQueue 对象。行 //3 创建引用其引用对象 MyObject 的 WeakReference 对象,还创建它的 ReferenceQueue。请注意,每个对象引用(obj、rq 及 wr)都是强引用。要利用这些引用类,您必须取消对 MyObject 对象的强引用,方法是将 obj 设置为 null。前面说过,如果不这样做,对象 MyObject 永远都不会被回收,引用类的任何优点都会被削弱。

每个引用类都有一个 get() 方法,而 ReferenceQueue 类有一个 poll() 方法。get() 方法返回对被引用对象的引用。在 PhantomReference 上调用 get() 总是会返回 null。这是因为 PhantomReference 只用于跟踪收集。poll() 方法返回已被添加到队列中的引用对象,如果队列中没有任何对象,它就返回 null。因此,执行清单 1 之后再调用 get() 和 poll() 的结果可能是:


wr.get(); //returns reference to MyObject
rq.poll(); //returns null




现在我们假定垃圾收集器开始运行。由于 MyObject 对象没有被释放,所以 get() 和 poll() 方法将返回同样的值;obj 仍然保持对该对象进行强引用。实际上,对象布局还是没有改变,和图 1 所示的差不多。然而,请考虑下面的代码:


obj = null;
System.gc(); //run the collector







现在,调用 get() 和 poll() 将产生与前面不同的结果:


wr.get(); //returns null
rq.poll(); //returns a reference to the WeakReference object




这种情况表明,MyObject 对象(对它的引用原来是由 WeakReference 对象进行的)不再可用。这意味着垃圾收集器释放了 MyObject 占用的内存,从而使 WeakReference 对象可以被放在它的 ReferenceQueue 上。这样,您就可以知道当 WeakReference 或 SoftReference 类的 get() 方法返回 null 时,就有一个对象被声明为 finalizable,而且可能(不过不一定)被收集。只有当 heap 对象完全结束而且其内存被回收后,WeakReference 或 SoftReference 才会被放到与其关联的 ReferenceQueue 上。清单 2 显示了一个完整的可运行程序,它展示了这些原理中的一部分。这段代码本身就颇具说明性,它含有很多注释和打印语句,可以帮助您理解。

清单 2. 展示引用类原理的完整程序
import java.lang.ref.*;
class MyObject
{
protected void finalize() throws Throwable
{
System.out.println("In finalize method for this object: " +
this);
}
}

class ReferenceUsage
{
public static void main(String args[])
{
hold();
release();
}

public static void hold()
{
System.out.println("Example of incorrectly holding a strong " +
"reference");
//Create an object
MyObject obj = new MyObject();
System.out.println("object is " + obj);

//Create a reference queue
ReferenceQueue rq = new ReferenceQueue();

//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq);

System.out.println("The weak reference is " + wr);

//Check to see if it´s on the ref queue yet
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());

System.out.println("Calling GC");
System.gc();
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
}

public static void release()
{
System.out.println("");
System.out.println("Example of correctly releasing a strong " +
"reference");
//Create an object
MyObject obj = new MyObject();
System.out.println("object is " + obj);

//Create a reference queue
ReferenceQueue rq = new ReferenceQueue();

//Create a weakReference to obj and associate our reference queue
WeakReference wr = new WeakReference(obj, rq);

System.out.println("The weak reference is " + wr);

//Check to see if it´s on the ref queue yet
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());

System.out.println("Set the obj reference to null and call GC");
obj = null;
System.gc();
System.out.println("Polling the reference queue returns " +
rq.poll());
System.out.println("Getting the referent from the " +
"weak reference returns " + wr.get());
}
}




用途和风格
这些类背后的原理就是避免在应用程序执行期间将对象留在内存中。相反,您以软引用、弱引用或虚引用的方式引用对象,这样垃圾收集器就能够随意地释放对象。当您希望尽可能减小应用程序在其生命周期中使用的堆内存大小时,这种用途就很有好处。您必须记住,要使用这些类,您就不能保留对对象的强引用。如果您这么做了,那就会浪费这些类所提供的任何好处。

另外,您必须使用正确的编程风格以检查收集器在使用对象之前是否已经回收了它,如果已经回收了,您首先必须重新创建该对象。这个过程可以用不同的编程风格来完成。选择错误的风格会导致出问题。请考虑清单 3 中从 WeakReference 检索被引用对象的代码风格:

清单 3. 检索被引用对象的风格
obj = wr.get();
if (obj == null)
{
wr = new WeakReference(recreateIt()); //1
obj = wr.get(); //2
}
//code that works with obj




研究了这段代码之后,请看看清单 4 中从 WeakReference 检索被引用对象的另一种代码风格:

清单 4. 检索被引用对象的另一种风格
obj = wr.get();
if (obj == null)
{
obj = recreateIt(); //1
wr = new WeakReference(obj); //2
}
//code that works with obj




请比较这两种风格,看看您能否确定哪种风格一定可行,哪一种不一定可行。清单 3 中体现出的风格不一定在所有情况下都可行,但清单 4 的风格就可以。清单 3 中的风格不够好的原因在于,if 块的主体结束之后 obj 不一定是非空值。请考虑一下,如果垃圾收集器在清单 3 的行 //1 之后但在行 //2 执行之前运行会怎样。recreateIt() 方法将重新创建该对象,但它会被 WeakReference 引用,而不是强引用。因此,如果收集器在行 //2 在重新创建的对象上施加一个强引用之前运行,对象就会丢失,wr.get() 则返回 null。

清单 4 不会出现这种问题,因为行 //1 重新创建了对象并为其指定了一个强引用。因此,如果垃圾收集器在该行之后(但在行 //2 之前)运行,该对象就不会被回收。然后,行 //2 将创建对 obj 的 WeakReference。在使用这个 if 块之后的 obj 之后,您应该将 obj 设置为 null,从而让垃圾收集器能够回收这个对象以充分利用弱引用。清单 5 显示了一个完整的程序,它将展示刚才我们描述的风格之间的差异。(要运行该程序,其运行目录中必须有一个“temp.fil”文件。

清单 5. 展示正确的和不正确的编程风格的完整程序。
import java.io.*;
import java.lang.ref.*;

class ReferenceIdiom
{
public static void main(String args[]) throws FileNotFoundException
{
broken();
correct();
}

public static FileReader recreateIt() throws FileNotFoundException
{
return new FileReader("temp.fil");
}

public static void broken() throws FileNotFoundException
{
System.out.println("Executing method broken");
FileReader obj = recreateIt();
WeakReference wr = new WeakReference(obj);

System.out.println("wr refers to object " + wr.get());

System.out.println("Now, clear the reference and run GC");
//Clear the strong reference, then run GC to collect obj.
obj = null;
System.gc();

System.out.println("wr refers to object " + wr.get());

//Now see if obj was collected and recreate it if it was.
obj = (FileReader)wr.get();
if (obj == null)
{
System.out.println("Now, recreate the object and wrap it
in a WeakReference");
wr = new WeakReference(recreateIt());
System.gc(); //FileReader object is NOT pinned...there is no
//strong reference to it. Therefore, the next
//line can return null.
obj = (FileReader)wr.get();
}
System.out.println("wr refers to object " + wr.get());
}

public static void correct() throws FileNotFoundException
{
System.out.println("");
System.out.println("Executing method correct");
FileReader obj = recreateIt();
WeakReference wr = new WeakReference(obj);

System.out.println("wr refers to object " + wr.get());

System.out.println("Now, clear the reference and run GC");
//Clear the strong reference, then run GC to collect obj
obj = null;
System.gc();

System.out.println("wr refers to object " + wr.get());

//Now see if obj was collected and recreate it if it was.
obj = (FileReader)wr.get();
if (obj == null)
{
System.out.println("Now, recreate the object and wrap it
in a WeakReference");
obj = recreateIt();
System.gc(); //FileReader is pinned, this will not affect
//anything.
wr = new WeakReference(obj);
}
System.out.println("wr refers to object " + wr.get());
}
}




总结
如果使用得当,引用类还是很有用的。然而,由于它们所依赖的垃圾收集器行为有时候无法预知,所以其实用性就会受到影响。能否有效地使用它们还取决于是否应用了正确的编程风格;关键在于您要理解这些类是如何实现的以及如何对它们进行编程。
=================================================================================

Java 对象的状态有:

    * 已创建(created)
    * 强可达(strong reachable)
    * 不可见(invisible)
    * 不可达(unreachable)
    * 已收集(collected)
    * 终化(finalized)
    * 已回收(deallocated) 

Java对象生命周期的状态转换: {image:img=objectstatus.jpg|width=400} 引用对象
三种新的引用类型:

    * 软引用(soft reference)
    * 弱引用(weak reference)
    * 幻引用(phantom reference) 

强可达(Strong Reachable)
定义: ~An object is strong reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strong reachable by the thread that created it.~
处于强可达状态的对象, 在任何情况下都不会被回收掉. 软可达(Softly Reachable)
定义:~An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.~
含义是:当对象不处于强可达状态, 并且可以通过软引用进行访问时, 即处于软可达状态.
当程序申请内存的时候, 垃圾收集器会判断是否开始回收处于软可达状态的对象, 如果决定回收某个对象, 那么垃圾收集器会清除所有指向该对象的软引用, 如果任何处于其它软可达状态的对象可以通过强引用访问该对象, 那么指向这些对象的软引用也会被清除掉. 垃圾收集器在决定哪些软可达状态的对象被收集时, 采用"最久未被使用"原则, 或称"最不常使用"原则. 垃圾收集器也保证在OutOfMemeryError产生以前, 所有的软引用都被清除.

    * 产生和使用一个软引用 

// createSoftReference sr = new SoftReference(new SomeObject());// getSomeObject o = (SomeObject) sf.get();// create in a reference queue;ReferenceQueue queue = new ReferenceQueue();SoftReference sr = new SoftReference(new SomeObject(), queue);

弱可达(Weakly Reachable)
定义:~An Object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference.~
垃圾收集器会一次清除所有弱引用. 幻可达(Phantomly Reachable)
定义:~An object is phantomly reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.~
幻引用不能直接创建. 必须通过向引用队列等级的途径来创建:

ReferenceQueue queue = new ReferenceQueue();PhantomReference pr = new PhantomReference (new SomeObject(), queue);

你不可能从幻引用再次得到对象, pr.get()永远返回null. 另外, 必须调用Reference.clear()手工清除幻引用. All About ReferenceObjects No InterWiki reference defined in properties for Wiki called '[http'!)]
Reference Objects No InterWiki reference defined in properties for Wiki called '[http'!)]
Reference Objects and Garbage Collection No InterWiki reference defined in properties for Wiki called '[http'!)]
\[Jike Thread\?Soft, Weak, and Phantom References|http://www-124.ibm.com/pipermail/jikesrvm-core/2003-May/000365.html]


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1492810
posted @ 2008-12-06 21:13 竹子 阅读(476) | 评论 (0)编辑 收藏

T-SQL 编码标准

发布日期: 4/15/2005 | 更新日期: 4/15/2005

Brian Walker

可能让人觉得很奇怪,但好像的确没有什么正式的”T-SQL 编码标准。早在 1999 年末的时候,我惊喜地发现 John Hindmarsh 提出的 SQL Server 7.0 标准,我在 2000 2 月的社论中对他的某些建议进行了总结。(2000 2 月以及本月的下载中都包括了 John 原来的标准。)后来,Ron Talmage 撰写了一系列专栏文章,提出了他对各种最佳方法的建议,当然,SQL Server 小组也已正式发布了 SQL Server 最佳方法分析器 (SQLBPA)。现在,一位具有超过 25 年经验的数据库管理员和应用程序开发员 Brian Walker 又提出了他的建议和提示。

*

进行 T-SQL 编程时常常会忽略编码标准,但这些标准却是开发小组顺利开展工作的关键工具。这里介绍的编码标准是我多年的开发成果。它们当然还没有得到普遍接受,而且不可否认,有些标准带有主观色彩。我的目的实际上更多的是为了提高大家的意识,而不是吹捧自己是 T-SQL 样式方面的仲裁者:最重要的是要建立某些合理的编码标准并遵循这些标准。您在这篇文章中会发现有关 T-SQL 编程的一系列不同的编码标准、技巧和提示。它们并未以任何特定的优先级或重要性顺序列出。

让我们从格式开始。表面上,T-SQL 代码的格式似乎并不重要,但一致的格式可以使您的同事(不论是同一小组的成员还是更大范围的 T-SQL 开发团队的成员)更轻松地浏览和理解您的代码。T-SQL 语句有一个结构,遵循一目了然的结构使您可以更轻松地查找和确认语句的不同部分。统一的格式还使您可以更轻松地在复杂 T-SQL 语句中增删代码段,使调试工作变得更容易。下面是 SELECT 语句的格式示例:

       SELECT C.Name
, E.NameLast
, E.NameFirst
, E.Number
, ISNULL(I.Description,'NA') AS Description
FROM tblCompany AS C
JOIN tblEmployee AS E
ON C.CompanyID = E.CompanyID
LEFT JOIN tblCoverage AS V
ON E.EmployeeID = V.EmployeeID
LEFT JOIN tblInsurance AS I
ON V.InsuranceID = I.InsuranceID
WHERE C.Name LIKE @Name
AND V.CreateDate > CONVERT(smalldatetime,
'01/01/2000')
ORDER BY C.Name
, E.NameLast
, E.NameFirst
, E.Number
, ISNULL(I.Description,'NA')
SELECT @Retain = @@ERROR, @Rows = @@ROWCOUNT
IF @Status = 0 SET @Status = @Retain

►一个嵌套代码块中的语句使用四个空格的缩进。(上述代码中的多行 SELECT 语句是一个 SQL 语句。)在同一语句中开始新行时,使 SQL 关键字右对齐。将代码编辑器配置为使用空格,而不是使用制表符。这样,不管使用何种程序查看代码,格式都是一致的。

►大写所有的 T-SQL 关键字,包括 T-SQL 函数。变量名称及光标名称使用混和大小写。数据类型使用小写。

►表名别名要简短,但意义要尽量明确。通常,使用大写的表名作为别名,使用 AS 关键字指定表或字段的别名。

►当一个 T-SQL 语句中涉及到多个表时,始终使用表名别名来限定字段名。这使其他人阅读起来更清楚,避免了含义模糊的引用。

►当相关数字出现在连续的代码行中时(例如一系列 SUBSTRING 函数调用),将它们排成列。这样容易浏览数字列表。

►使用一个(而不是两个)空行分隔 T-SQL 代码的逻辑块,只要需要就可以使用。

►声明 T-SQL 局部变量(例如 @lngTableID)时,使用适当的数据类型声明和一致的大写。

始终指定字符数据类型的长度,并确保允许用户可能需要的最大字符数,因为超出最大长度的字符会丢失。

始终指定十进制数据类型的精度和范围,否则,将默认为未指定精度和整数范围。

►使用错误处理程序,但要记住行首 (BOL) 中的错误检查示例不会象介绍的那样起作用。用来检查 @@ERROR 系统函数的 T-SQL 语句 (IF) 实际上在进程中清除了 @@ERROR 值,无法再捕获除零之外的任何值。(即使示例起作用,它们也只能捕获最后发生的一个错误,而不是您更想捕获的第一个错误。)必须使用 SET 或 SELECT 立即捕获错误代码,如前面示例所示。如果状态变量仍然为零,应转换到状态变量。

►避免使用“未声明的”功能,例如系统表中未声明的列、T-SQL 语句中未声明的功能或者未声明的系统存储过程或扩展的存储过程。

不要依赖任何隐式的数据类型转换。例如,不能为数字变量赋予字符值,而假定 T-SQL 会进行必要的转换。相反,在为变量赋值或比较值之前,应使用适当的 CONVERT 函数使数据类型相匹配。另一个示例:虽然 T-SQL 会在进行比较之前对字符表达式进行隐式且自动的 RTRIM,但不能依赖此行为,因为兼容性级别设置非字符表达式会使情况复杂化。

不要将空的变量值直接与比较运算符(符号)比较。如果变量可能为空,应使用 IS NULL 或 IS NOT NULL 进行比较,或者使用 ISNULL 函数。

►不要使用 STR 函数进行舍入,此函数只能用于整数。如果需要十进制值的字符串形式,应先使用 CONVERT 函数(转至不同的范围)或 ROUND 函数,然后将其转换为字符串。也可以使用 CEILING 和 FLOOR 函数。

►使用数学公式时要小心,因为 T-SQL 可能会将表达式强制理解为一个不需要的数据类型。如果需要十进制结果,应在整数常量后加点和零 (.0)。

►决不要依赖 SELECT 语句会按任何特定顺序返回行,除非在 ORDER BY 子句中指定了顺序。

►通常,应将 ORDER BY 子句与 SELECT 语句一起使用。可预知的顺序(即使不是最方便的)比不可预知的顺序强,尤其是在开发或调试过程中。(部署到生产环境中之前,可能需要删除 ORDER BY 子句。)在返回行的顺序无关紧要的情况下,可以忽略 ORDER BY 的开销。

►不要在 T-SQL 代码中使用双引号。应为字符常量使用单引号。如果没有必要限定对象名称,可以使用(非 ANSI SQL 标准)括号将名称括起来。

►在 SQL Server 2000 中,尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

►先在例程中创建临时表,最后再显式删除临时表。将 DDL 与 DML 语句混合使用有助于处理额外的重新编译活动。

►要认识到临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。

使用表值 UDF 时要小心,因为在变量(而不是常量)中传递某个参数时,如果在 WHERE 子句中使用该参数,会导致表扫描。还要避免在一个查询中多次使用相同的表值 UDF。但是,表值 UDF 确实具有某些非常方便的动态编译功能。[相关资料:参阅 Tom Moreau 2003 11 月份生成序列号专栏中的使用 UDF 填充表变量。-编者按]

►几乎所有的存储过程都应在开始时设置 SET NOCOUNT ON,而在结束时设置 SET NOCOUNT OFF。[SET NOCOUNT ON 使 SQL Server 无需在执行存储过程的每个语句后向客户端发送 DONE_IN_PROC 消息。- 编者按] 此标准同样适用于触发器。

►只要在例程中使用多个数据库修改语句,包括在一个循环中多次执行一个语句,就应考虑声明显式事务。

►使用基于光标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题。基于集的方法通常更有效。

►与临时表一样,光标并不是不可使用。对小型数据集使用 FAST_FORWARD 光标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用光标执行的速度快。如果开发时间允许,基于光标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

►使用包含序号(从 1 到 N)的表很方便。

►理解 CROSS JOIN 的工作原理并加以利用。例如,您可以在工作数据表和序号表之间有效地使用 CROSS JOIN,结果集中将包含每个工作数据与序号组合的记录。

►我的结束语是:T-SQL 代码往往很简洁,因此如果某个代码块看起来很难处理或重复内容较多,那么可能存在一种更简单,更好的方法。

结论

如果您对我的建议有任何看法,欢迎随时向我发送电子邮件进行讨论,也可以就其他问题提出您的建议。我希望您将此作为谈话的开场白。

其他信息:摘自 Karen 2000 2 月份的社论

在标准开发的前沿阵地上,有一股以 SQL Server 数据库管理员 John Hindmarsh 为首的独立的新生力量。MCT、MCSE 和 MCDBA 都是最值得您花时间去研究的。John 的贡献是撰写了一份详细的白皮书,概述了他对各种 SQL Server 相关标准提出的建议。我所知道的其他唯一提出类似建议的文章是 Andrew Zanevsky 的《Transact-SQL Programming》(ISBN 1-56592-401-0) 中的“Format and Style”一章。Andrew、SQL Server Professional 的投稿人 Tom Moreau 和 Paul Munkenbeck 以及 John 的朋友兼同事 Stephen James 都为 John 的白皮书做出过贡献。下面是 John 为编写存储过程提供的建议示例:

使用 SQL-92 标准连接句法。

为了提高性能,应优先使用连接,然后使用子查询或嵌套查询。

确保变量和参数的类型和大小与表数据列相匹配。

确保使用所有变量和参数,或者全部删除。

尽可能将临时对象放置在本地。

只使用在存储过程中创建的临时表。

检查输入参数的有效性。

优先使用 SELECT...INTO,然后使用 INSERT...SELECT,以避免大量死锁。

维护工作需要的逻辑单元;在可以缩短的情况下,不要创建大量或长时间运行的进程。

不要在任何代码中使用 SELECT *。

在过程中使用缩进、块、制表符和空格(参阅示例脚本)。

T-SQL 语句要大写。

在过程中添加大量注释,确保可以识别进程。在有助于澄清处理步骤的地方使用行注释。

包括事务管理,除非要从 MTS 进程中调用过程。(为 MTS 进程编写独立的过程。)

监视 @@TRANCOUNT 以确定事务的责任级别。

避免使用 GOTO,错误处理程序中除外。

避免使用嵌套过程。

避免隐式解析对象名称,确保所有对象都归 dbo 所有。

下载 412BRIAN.ZIP

链接至www.microsoft.com/downloads/details.aspx?displayla%20ng=en&familyid=B352EB1F-D3CA-44EE-893E-9E07339C1F22&displaylang=en

有关 SQL Server Professional 和 Pinnacle Publishing 的详细信息,请访问其 Web 站点 http://www.pinpub.com/

注意:这不是 Microsoft Corporation 的 Web 站点。Microsoft 对该 Web 站点上的内容不承担任何责任。

本文转载自 2004 年 12 月份的 SQL Server Professional。除非另行说明,否则版权所有 2004 Pinnacle Publishing, Inc.。保留所有权利。SQL Server Professional 是 Pinnacle Publishing 独立发行的刊物。未经 Pinnacle Publishing, Inc. 事先同意,不得以任何方式使用或复制本文的任何部分(评论文章中的简短引用除外)。如需与 Pinnacle Publishing, Inc. 联系,请拨打 1-800-788-1900。

© 2005 Microsoft Corporation 版权所有。保留所有权利。使用规定。

原文出处:http://www.microsoft.com/china/msdn/library/data/sqlserver/sp04l9.mspx?mfr=true

posted @ 2008-12-02 10:50 竹子 阅读(349) | 评论 (0)编辑 收藏
  1      选择最有效率的表名顺序(只在基于规则的优化器中有效)

ORACLE 的解析器按照从右到左的顺序处理FROM子句中的表名,FROM子句中写在最后的表(基础表 driving table)将被最先处理,在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。如果有3个以上的表连接查询, 那就需要选择交叉表(intersection table)作为基础表, 交叉表是指那个被其他表所引用的表.

2      WHERE子句中的连接顺序.:

ORACLE采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前, 那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.

3      SELECT子句中避免使用 * ‘:

ORACLE在解析的过程中, 会将'*' 依次转换成所有的列名, 这个工作是通过查询数据字典完成的, 这意味着将耗费更多的时间

4      减少访问数据库的次数:

ORACLE在内部执行了许多工作: 解析SQL语句, 估算索引的利用率, 绑定变量 , 读数据块等;

5      SQL*Plus , SQL*FormsPro*C中重新设置ARRAYSIZE参数, 可以增加每次数据库访问的检索数据量 ,建议值为200

6      使用DECODE函数来减少处理时间:

使用DECODE函数可以避免重复扫描相同记录或重复连接相同的表.

7      整合简单,无关联的数据库访问:

如果你有几个简单的数据库查询语句,你可以把它们整合到一个查询中(即使它们之间没有关系)

8      删除重复记录:

最高效的删除重复记录方法 ( 因为使用了ROWID)例子:

DELETE FROM EMP E WHERE E.ROWID > (SELECT MIN(X.ROWID)

FROM EMP X WHERE X.EMP_NO = E.EMP_NO);

9      TRUNCATE替代DELETE

当删除表中的记录时,在通常情况下, 回滚段(rollback segments ) 用来存放可以被恢复的信息. 如果你没有COMMIT事务,ORACLE会将数据恢复到删除之前的状态(准确地说是恢复到执行删除命令之前的状况) 而当运用TRUNCATE, 回滚段不再存放任何可被恢复的信息.当命令运行后,数据不能被恢复.因此很少的资源被调用,执行时间也会很短. (译者按: TRUNCATE只在删除全表适用,TRUNCATEDDL不是DML)

10 尽量多使用COMMIT

只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少:

COMMIT所释放的资源:

a. 回滚段上用于恢复数据的信息.

b. 被程序语句获得的锁

c. redo log buffer 中的空间

d. ORACLE为管理上述3种资源中的内部花费

11 Where子句替换HAVING子句:

避免使用HAVING子句, HAVING 只会在检索出所有记录之后才对结果集进行过滤. 这个处理需要排序,总计等操作. 如果能通过WHERE子句限制记录的数目,那就能减少这方面的开销. (oracle)onwherehaving这三个都可以加条件的子句中,on是最先执行,where次之,having最后,因为on是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据,按理说应该速度是最快的,where也应该比having快点的,因为它过滤数据后才进行sum,在两个表联接时才用on的,所以在一个表的时候,就剩下wherehaving比较了。在这单表查询统计的情况下,如果要过滤的条件没有涉及到要计算字段,那它们的结果是一样的,只是where可以使用rushmore技术,而having就不能,在速度上后者要慢如果要涉及到计算的字段,就表示在没计算之前,这个字段的值是不确定的,根据上篇写的工作流程,where的作用时间是在计算之前就完成的,而having就是在计算后才起作用的,所以在这种情况下,两者的结果会不同。在多表联接查询时,onwhere更早起作用。系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由where进行过滤,然后再计算,计算完后再由having进行过滤。由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里

12 减少对表的查询:

在含有子查询的SQL语句中,要特别注意减少对表的查询.例子:

     SELECT TAB_NAME FROM TABLES WHERE (TAB_NAME,DB_VER) = ( SELECT

TAB_NAME,DB_VER FROM TAB_COLUMNS WHERE VERSION = 604)

13 通过内部函数提高SQL效率.

复杂的SQL往往牺牲了执行效率. 能够掌握上面的运用函数解决问题的方法在实际工作中是非常有意义的

14 使用表的别名(Alias)

当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误.

15 EXISTS替代IN、用NOT EXISTS替代NOT IN

在许多基于基础表的查询中,为了满足一个条件,往往需要对另一个表进行联接.在这种情况下, 使用EXISTS(NOT EXISTS)通常将提高查询的效率. 在子查询中,NOT IN子句将执行一个内部的排序和合并. 无论在哪种情况下,NOT IN都是最低效的 (因为它对子查询中的表执行了一个全表遍历). 为了避免使用NOT IN ,我们可以把它改写成外连接(Outer Joins)NOT EXISTS.

例子:

(高效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND EXISTS (SELECT X' FROM DEPT WHERE DEPT.DEPTNO = EMP.DEPTNO AND LOC = MELB')

(低效)SELECT * FROM EMP (基础表) WHERE EMPNO > 0 AND DEPTNO IN(SELECT DEPTNO FROM DEPT WHERE LOC = MELB')

16 识别'低效执行'SQL语句:

虽然目前各种关于SQL优化的图形化工具层出不穷,但是写出自己的SQL工具来解决问题始终是一个最好的方法:

SELECT EXECUTIONS , DISK_READS, BUFFER_GETS,

ROUND((BUFFER_GETS-DISK_READS)/BUFFER_GETS,2) Hit_radio,

ROUND(DISK_READS/EXECUTIONS,2) Reads_per_run,

SQL_TEXT

FROM V$SQLAREA

WHERE EXECUTIONS>0

AND BUFFER_GETS > 0

AND (BUFFER_GETS-DISK_READS)/BUFFER_GETS < 0.8

ORDER BY 4 DESC;

17 用索引提高效率:

索引是表的一个概念部分,用来提高检索数据的效率,ORACLE使用了一个复杂的自平衡B-tree结构. 通常,通过索引查询数据比全表扫描要快. ORACLE找出执行查询和Update语句的最佳路径时, ORACLE优化器将使用索引. 同样在联结多个表时使用索引也可以提高效率. 另一个使用索引的好处是,它提供了主键(primary key)的唯一性验证.。那些LONGLONG RAW数据类型, 你可以索引几乎所有的列. 通常, 在大型表中使用索引特别有效. 当然,你也会发现, 在扫描小表时,使用索引同样能提高效率. 虽然使用索引能得到查询效率的提高,但是我们也必须注意到它的代价. 索引需要空间来存储,也需要定期维护, 每当有记录在表中增减或索引列被修改时, 索引本身也会被修改. 这意味着每条记录的INSERT , DELETE , UPDATE将为此多付出4 , 5 次的磁盘I/O . 因为索引需要额外的存储空间和处理,那些不必要的索引反而会使查询反应时间变慢.。定期的重构索引是有必要的.

ALTER INDEX <INDEXNAME> REBUILD <TABLESPACENAME>

18 EXISTS替换DISTINCT

当提交一个包含一对多表信息(比如部门表和雇员表)的查询时,避免在SELECT子句中使用DISTINCT. 一般可以考虑用EXIST替换, EXISTS 使查询更为迅速,因为RDBMS核心模块将在子查询的条件一旦满足后,立刻返回结果. 例子:

       (低效):

SELECT DISTINCT DEPT_NO,DEPT_NAME FROM DEPT D , EMP E

WHERE D.DEPT_NO = E.DEPT_NO

(高效):

SELECT DEPT_NO,DEPT_NAME FROM DEPT D WHERE EXISTS ( SELECT ‘X'

FROM EMP E WHERE E.DEPT_NO = D.DEPT_NO);

19 sql语句用大写的;因为oracle总是先解析sql语句,把小写的字母转换成大写的再执行

20 java代码中尽量少用连接符“+”连接字符串!

21 避免在索引列上使用NOT 通常, 

我们要避免在索引列上使用NOT, NOT会产生在和在索引列上使用函数相同的影响. ORACLE”遇到”NOT,他就会停止使用索引转而执行全表扫描.

22 避免在索引列上使用计算.

WHERE子句中,如果索引列是函数的一部分.优化器将不使用索引而使用全表扫描.

举例:

低效:

SELECT … FROM DEPT WHERE SAL * 12 > 25000;

高效:

SELECT … FROM DEPT WHERE SAL > 25000/12;

23 >=替代>

高效:

SELECT * FROM EMP WHERE DEPTNO >=4

低效:

SELECT * FROM EMP WHERE DEPTNO >3

两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录.

24 UNION替换OR (适用于索引列)

通常情况下, UNION替换WHERE子句中的OR将会起到较好的效果. 对索引列使用OR将造成全表扫描. 注意, 以上规则只针对多个索引列有效. 如果有column没有被索引, 查询效率可能会因为你没有选择OR而降低. 在下面的例子中, LOC_ID REGION上都建有索引.

高效:

SELECT LOC_ID , LOC_DESC , REGION

FROM LOCATION

WHERE LOC_ID = 10

UNION

SELECT LOC_ID , LOC_DESC , REGION

FROM LOCATION

WHERE REGION = “MELBOURNE”

低效:

SELECT LOC_ID , LOC_DESC , REGION

FROM LOCATION

WHERE LOC_ID = 10 OR REGION = “MELBOURNE”

如果你坚持要用OR, 那就需要返回记录最少的索引列写在最前面.

25 IN来替换OR 

这是一条简单易记的规则,但是实际的执行效果还须检验,在ORACLE8i下,两者的执行路径似乎是相同的. 

低效:

SELECT…. FROM LOCATION WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30

高效

SELECT… FROM LOCATION WHERE LOC_IN IN (10,20,30);

26 避免在索引列上使用IS NULLIS NOT NULL

避免在索引中使用任何可以为空的列,ORACLE将无法使用该索引.对于单列索引,如果列包含空值,索引中将不存在此记录. 对于复合索引,如果每个列都为空,索引中同样不存在此记录. 如果至少有一个列不为空,则记录存在于索引中.举例: 如果唯一性索引建立在表的A列和B列上, 并且表中存在一条记录的A,B值为(123,null) , ORACLE将不接受下一条具有相同A,B值(123,null)的记录(插入). 然而如果所有的索引列都为空,ORACLE将认为整个键值为空而空不等于空. 因此你可以插入1000 条具有相同键值的记录,当然它们都是空! 因为空值不存在于索引列中,所以WHERE子句中对索引列进行空值比较将使ORACLE停用该索引.

低效: (索引失效)

SELECT … FROM DEPARTMENT WHERE DEPT_CODE IS NOT NULL;

高效: (索引有效)

SELECT … FROM DEPARTMENT WHERE DEPT_CODE >=0;

27 总是使用索引的第一个列:

如果索引是建立在多个列上, 只有在它的第一个列(leading column)where子句引用时,优化器才会选择使用该索引. 这也是一条简单而重要的规则,当仅引用索引的第二个列时,优化器使用了全表扫描而忽略了索引

28 UNION-ALL 替换UNION ( 如果有可能的话)

SQL 语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最终结果前进行排序. 如果用UNION ALL替代UNION, 这样排序就不是必要了. 效率就会因此得到提高. 需要注意的是,UNION ALL 将重复输出两个结果集合中相同记录. 因此各位还是要从业务需求分析使用UNION ALL的可行性. UNION 将对结果集合排序,这个操作会使用到SORT_AREA_SIZE这块内存. 对于这块内存的优化也是相当重要的. 下面的SQL可以用来查询排序的消耗量

低效:

SELECT ACCT_NUM, BALANCE_AMT

FROM DEBIT_TRANSACTIONS

WHERE TRAN_DATE = '31-DEC-95'

UNION

SELECT ACCT_NUM, BALANCE_AMT

FROM DEBIT_TRANSACTIONS

WHERE TRAN_DATE = '31-DEC-95'

高效:

SELECT ACCT_NUM, BALANCE_AMT

FROM DEBIT_TRANSACTIONS

WHERE TRAN_DATE = '31-DEC-95'

UNION ALL

SELECT ACCT_NUM, BALANCE_AMT

FROM DEBIT_TRANSACTIONS

WHERE TRAN_DATE = '31-DEC-95'

29 WHERE替代ORDER BY

ORDER BY 子句只在两种严格的条件下使用索引.

ORDER BY中所有的列必须包含在相同的索引中并保持在索引中的排列顺序.

ORDER BY中所有的列必须定义为非空.

WHERE子句使用的索引和ORDER BY子句中所使用的索引不能并列.

例如:

DEPT包含以下列:

DEPT_CODE PK NOT NULL

DEPT_DESC NOT NULL

DEPT_TYPE NULL

低效: (索引不被使用)

SELECT DEPT_CODE FROM DEPT ORDER BY DEPT_TYPE

高效: (使用索引)

SELECT DEPT_CODE FROM DEPT WHERE DEPT_TYPE > 0

30 避免改变索引列的类型.:

当比较不同数据类型的数据时, ORACLE自动对列进行简单的类型转换.

假设 EMPNO是一个数值类型的索引列.

SELECT … FROM EMP WHERE EMPNO = ‘123'

实际上,经过ORACLE类型转换, 语句转化为:

SELECT … FROM EMP WHERE EMPNO = TO_NUMBER(‘123')

幸运的是,类型转换没有发生在索引列上,索引的用途没有被改变.

现在,假设EMP_TYPE是一个字符类型的索引列.

SELECT … FROM EMP WHERE EMP_TYPE = 123

这个语句被ORACLE转换为:

SELECT … FROM EMP WHERETO_NUMBER(EMP_TYPE)=123

因为内部发生的类型转换, 这个索引将不会被用到! 为了避免ORACLE对你的SQL进行隐式的类型转换, 最好把类型转换用显式表现出来. 注意当字符和数值比较时, ORACLE会优先转换数值类型到字符类型

31 需要当心的WHERE子句:

某些SELECT 语句中的WHERE子句不使用索引. 这里有一些例子.

在下面的例子里, (1)!=' 将不使用索引. 记住, 索引只能告诉你什么存在于表中, 而不能告诉你什么不存在于表中. (2) ||'是字符连接函数. 就象其他函数那样, 停用了索引. (3) +'是数学函数. 就象其他数学函数那样, 停用了索引. (4)相同的索引列不能互相比较,这将会启用全表扫描.

32 a. 如果检索数据量超过30%的表中记录数.使用索引将没有显著的效率提高.

b. 在特定情况下, 使用索引也许会比全表扫描慢, 但这是同一个数量级上的区别. 而通常情况下,使用索引比全表扫描要块几倍乃至几千倍!

33 避免使用耗费资源的操作:

带有DISTINCT,UNION,MINUS,INTERSECT,ORDER BYSQL语句会启动SQL引擎

执行耗费资源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要执行两次排序. 通常, 带有UNION, MINUS , INTERSECTSQL语句都可以用其他方式重写. 如果你的数据库的SORT_AREA_SIZE调配得好, 使用UNION , MINUS, INTERSECT也是可以考虑的, 毕竟它们的可读性很强

34 优化GROUP BY:

提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉.下面两个查询返回相同结果但第二个明显就快了许多.

低效:

SELECT JOB , AVG(SAL)

FROM EMP

GROUP JOB

HAVING JOB = ‘PRESIDENT'

OR JOB = ‘MANAGER'

高效:

SELECT JOB , AVG(SAL)

FROM EMP

WHERE JOB = ‘PRESIDENT'

OR JOB = ‘MANAGER'

GROUP JOB

posted @ 2008-12-02 10:42 竹子 阅读(200) | 评论 (0)编辑 收藏
 


l l 数据库回滚段是否足够?


l l 是否需要建立ORACLE数据库索引、聚集、散列?


l l 系统全局区(SGA)大小是否足够?


l l SQL语句是否高效?


2、2、数据仓库系统(Data Warehousing),这种信息系统的主要任务是从ORACLE的海量数据中进行查询,得到数据之间的某些规律。数据库管理员需要为这种类型的ORACLE数据库着重考虑下述参数:


l l 是否采用B*-索引或者bitmap索引?


l l 是否采用并行SQL查询以提高查询效率?


l l 是否采用PL/SQL函数编写存储过程?


l l 有必要的话,需要建立并行数据库提高数据库的查询效率


SQL语句的调整原则


SQL语言是一种灵活的语言,相同的功能可以使用不同的语句来实现,但是语句的执行效率是很不相同的。程序员可以使用EXPLAIN PLAN语句来比较各种实现方案,并选出最优的实现方案。总得来讲,程序员写SQL语句需要满足考虑如下规则:


1、1、尽量使用索引。试比较下面两条SQL语句:


语句A:SELECT dname, deptno FROM dept WHERE deptno NOT IN


(SELECT deptno FROM emp);


语句B:SELECT dname, deptno FROM dept WHERE NOT EXISTS


(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno);


这两条查询语句实现的结果是相同的,但是执行语句A的时候,ORACLE会对整个emp表进行扫描,没有使用建立在emp表上的deptno索引,执行语句B的时候,由于在子查询中使用了联合查询,ORACLE只是对emp表进行的部分数据扫描,并利用了deptno列的索引,所以语句B的效率要比语句A的效率高一些。


2、2、选择联合查询的联合次序。考虑下面的例子:


SELECT stuff FROM taba a, tabb b, tabc c


WHERE a.acol between :alow and :ahigh


AND b.bcol between :blow and :bhigh


AND c.ccol between :clow and :chigh


AND a.key1 = b.key1


AMD a.key2 = c.key2;


这个SQL例子中,程序员首先需要选择要查询的主表,因为主表要进行整个表数据的扫描,所以主表应该数据量最小,所以例子中表A的acol列的范围应该比表B和表C相应列的范围小。


3、3、在子查询中慎重使用IN或者NOT IN语句,使用where (NOT) exists的效果要好的多。


4、4、慎重使用视图的联合查询,尤其是比较复杂的视图之间的联合查询。一般对视图的查询最好都分解为对数据表的直接查询效果要好一些。


5、5、可以在参数文件中设置SHARED_POOL_RESERVED_SIZE参数,这个参数在SGA共享池中保留一个连续的内存空间,连续的内存空间有益于存放大的SQL程序包。


6、6、ORACLE公司提供的DBMS_SHARED_POOL程序可以帮助程序员将某些经常使用的存储过程“钉”在SQL区中而不被换出内存,程序员对于经常使用并且占用内存很多的存储过程“钉”到内存中有利于提高最终用户的响应时间。


CPU参数的调整


CPU是服务器的一项重要资源,服务器良好的工作状态是在工作高峰时CPU的使用率在90%以上。如果空闲时间CPU使用率就在90%以上,说明服务器缺乏CPU资源,如果工作高峰时CPU使用率仍然很低,说明服务器CPU资源还比较富余。


使用操作相同命令可以看到CPU的使用情况,一般UNIX操作系统的服务器,可以使用sar –u命令查看CPU的使用率,NT操作系统的服务器,可以使用NT的性能管理器来查看CPU的使用率。


数据库管理员可以通过查看v$sysstat数据字典中“CPU used by this session”统计项得知ORACLE数据库使用的CPU时间,查看“OS User level CPU time”统计项得知操作系统用户态下的CPU时间,查看“OS System call CPU time”统计项得知操作系统系统态下的CPU时间,操作系统总的CPU时间就是用户态和系统态时间之和,如果ORACLE数据库使用的CPU时间占操作系统总的CPU时间90%以上,说明服务器CPU基本上被ORACLE数据库使用着,这是合理,反之,说明服务器CPU被其它程序占用过多,ORACLE数据库无法得到更多的CPU时间。


数据库管理员还可以通过查看v$sesstat数据字典来获得当前连接ORACLE数据库各个会话占用的CPU时间,从而得知什么会话耗用服务器CPU比较多。


出现CPU资源不足的情况是很多的:SQL语句的重解析、低效率的SQL语句、锁冲突都会引起CPU资源不足。


1、数据库管理员可以执行下述语句来查看SQL语句的解析情况:


SELECT * FROM V$SYSSTAT


WHERE NAME IN


('parse time cpu', 'parse time elapsed', 'parse count (hard)');


这里parse time cpu是系统服务时间,parse time elapsed是响应时间,用户等待时间


waite time = parse time elapsed – parse time cpu


由此可以得到用户SQL语句平均解析等待时间=waite time / parse count。这个平均等待时间应该接近于0,如果平均解析等待时间过长,数据库管理员可以通过下述语句


SELECT SQL_TEXT, PARSE_CALLS, EXECUTIONS FROM V$SQLAREA


ORDER BY PARSE_CALLS;


来发现是什么SQL语句解析效率比较低。程序员可以优化这些语句,或者增加ORACLE参数SESSION_CACHED_CURSORS的值。


2、数据库管理员还可以通过下述语句:


SELECT BUFFER_GETS, EXECUTIONS, SQL_TEXT FROM V$SQLAREA;


查看低效率的SQL语句,优化这些语句也有助于提高CPU的利用率。


3、3、数据库管理员可以通过v$system_event数据字典中的“latch free”统计项查看ORACLE数据库的冲突情况,如果没有冲突的话,latch free查询出来没有结果。如果冲突太大的话,数据库管理员可以降低spin_count参数值,来消除高的CPU使用率。


内存参数的调整


内存参数的调整主要是指ORACLE数据库的系统全局区(SGA)的调整。SGA主要由三部分构成:共享池、数据缓冲区、日志缓冲区。


1、 1、 共享池由两部分构成:共享SQL区和数据字典缓冲区,共享SQL区是存放用户SQL命令的区域,数据字典缓冲区存放数据库运行的动态信息。数据库管理员通过执行下述语句:


select (sum(pins - reloads)) / sum(pins) "Lib Cache" from v$librarycache;


来查看共享SQL区的使用率。这个使用率应该在90%以上,否则需要增加共享池的大小。数据库管理员还可以执行下述语句:


select (sum(gets - getmisses - usage - fixed)) / sum(gets) "Row Cache" from v$rowcache;


查看数据字典缓冲区的使用率,这个使用率也应该在90%以上,否则需要增加共享池的大小。


2、 2、 数据缓冲区。数据库管理员可以通过下述语句:


SELECT name, value FROM v$sysstat WHERE name IN ('db block gets', 'consistent gets','physical reads');


来查看数据库数据缓冲区的使用情况。查询出来的结果可以计算出来数据缓冲区的使用命中率=1 - ( physical reads / (db block gets + consistent gets) )。


这个命中率应该在90%以上,否则需要增加数据缓冲区的大小。


3、 3、 日志缓冲区。数据库管理员可以通过执行下述语句:


select name,value from v$sysstat where name in ('redo entries','redo log space requests');查看日志缓冲区的使用情况。查询出的结果可以计算出日志缓冲区的申请失败率:

申请失败率=requests/entries,申请失败率应该接近于0,否则说明日志缓冲区开设太小,需要增加ORACLE数据库的日志缓冲区。
posted @ 2008-11-20 09:47 竹子 阅读(359) | 评论 (0)编辑 收藏
本文描述了Oracle 的查询优化程序,它是数据的关键组件,能让Oracle用户获得极佳的执行性能。Oracle 的查询优化技术功能上无与伦比,本文详细讨论了查询优化的所有重要领域。

  简介

  什么是查询优化程序?

  查询优化对于关系数据库的性能,特别是对于执行复杂SQL 语句的性能而言至关重要。查询优化程序确定执行每一次查询的最佳策略。

  例如,查询优化程序选择对于指定的查询是否使用索引,以及在联接多个表时采用哪一种联接技术。这类决策对SQL 语句的执行性能有很大的影响,查询优化对于每一种应用程序都是关键技术,应用程序涉及的范围从操作系统到数据仓库,从分析系统到内容管理系统。查询优化程序对于应用程序和最终用户是完全透明的。

  由于应用程序可能生成非常复杂的SQL 语句, 查询优化程序必须精心构建、功能强大,以保障良好的执行性能。例如,查询优化程序可转换SQL 语句,使复杂的语句转换成为等价的但执行性能更好的SQL 语句。查询优化程序的典型特征是基于开销。在基于开销的优化策略中,对于给定查询生成多个执行计划,然后对每个计划估算开销。查询优化程序选用估算开销最低的计划。

  Oracle 在查询优化方面提供了什么?

  Oracle 的优化程序可称是业界最成功的优化程序。基于开销的优化程序自1992 年随Oracle7 推出后,通过10 年的丰富的实际用户经验,不断得到提高和改进。好的查询优化程序不是基于纯粹的理论假设及谓词在实验室中开发出来的,而是通过适合实际用户需求开发和磨合出来的。

  Oracle 的查询优化程序比任何其他查询优化程序在数据库应用程序的应用都要多,而且Oracle 的优化程序一直由于实际应用的反馈而得到改进。

  Oracle 的优化程序包含4 大主要部分(本文将在以下章节详细讨论这些部分):

  SQL 语句转换:在查询优化中Oracle 使用一系列精深技术对SQL 语句进行转换。查询优化的这一步骤的目的是将原有的SQL 语句转换成为语义相同而处理效率更高的SQL 语句。

  执行计划选择:对于每个SQL 语句, 优化程序选择一个执行计划(可使用Oracle 的EXPLAIN PLAN 工具或通过Oracle 的“v$sql_plan” 视图查看)。执行计划描述了执行SQL 时的所有步骤,如访问表的顺序;如何将这些表联接在一起;以及是否通过索引来访问这些表。优化程序为每个SQL 语句设计许多可能的执行计划,并选出最好的一个。

  开销模型与统计:Oracle 的优化程序依赖于执行SQL 语句的所有单个操作的开销估算。想要优化程序能选出最好的执行计划,需要最好的开销估算方法。开销估算需要详细了解某些知识,这些知识包括:明白每个查询所需的I/O、CPU 和内存资源以及数据库对象相关的统计信息(表、索引和物化视图),还有有关硬件服务平台的性能信息。收集这些统计和性能信息的过程应高效并且高度自动化。

  动态运行时间优化:并不是SQL 执行的每个方面都可以事先进行优化。Oracle 因此要根据当前数据库负载对查询处理策略进行动态调整。该动态优化的目标是获得优化的执行性能,即使每个查询可能不能够获得理想的CPU 或内存资源。Oracle 另有一个原来的优化程序,即基于规则的优化程序。该优化程序仅向后兼容,在Oracle 的下个版本将不再得到支持。绝大多数Oracle 用户目前使用基于开销的优化程序。所有主要的应用程序供应商(如Oracle 应用程序、SAP 和Peoplesoft,仅列出这几家)以及大量近来开发的客户应用程序都使用基于开销的优化程序来获得优良的执行性能,故本文仅讲述基于开销的优化程序。

  SQL 语句转换

  使用SQL 语句表示复杂查询可以有多种方式。提交到数据库的SQL 语句类型通常是最终用户或应用程序可以最简单的方式生成的SQL 类型。但是这些人工编写或机器生成的查询公式不一定是执行查询最高效的SQL 语句。例如,由应用程序生成的查询通常含有一些无关紧要的条件,这些条件可以去掉。或者,有些从某查询谓词出的附加条件应当添加到该SQL 语句中。SQL 转换语句的目的是将给定的SQL 语句转换成语义相同(即返回相同结果的SQL 语句)并且性能更好的SQL 语句。

  所有的这些转换对应用程序及最终用户完全透明。SQL 语句转换在查询优化过程中自动实现。

  Oracle 实现了多种SQL 语句转换。这些转换大概可分成两类:

  试探查询转换:在可能的情况下对进来的SQL 语句都会进行这种转换。这种转换能够提供相同或较好的查询性能,所以Oracle 知道实施这种转换不会降低执行性能。 基于开销的查询转换:Oracle 使用基于开销的方法进行几类查询转换。借助这种方法,转换后的查询会与原查询相比较,然后Oracle 的优化程序从中选出最佳执行策略。

  以下部分将讨论Oracle 转换技术的几个示例。这些示例并非是权威的,仅用于帮助读者理解该关键转换技术及其益处。

  试探查询转换

  简单视图合并

  可能最简单的查询转换是视图合并。对于包含视图的查询,通常可以通过把视图定义与查询“合并”来将视图从查询中去掉。例如,请看下面的非常简单的视图及查询。

  CREATE VIEW TEST_VIEW AS SELECT ENAME, DNAME, SAL FROM EMP E, DEPT D WHERE E.DEPTNO = D.DEPTNO;
  SELECT ENAME, DNAME FROM TEST_VIEW WHERE SAL > 10000;

  如果不加任何转换,处理该查询的唯一方法是将EMP 的所有行联接到DEPT 表的所有行,然后筛选有适当的SAL 的值的那些行。

  如果使用视图合并,上述查询可以转换为:

  SELECT ENAME, DNAME FROM EMP E, DEPT D WHERE E.DEPTNO = D.DEPTNO AND E.SAL > 10000;

  处理该转换后的查询时,可以在联接EMP 和DEPT 表前使用谓词‘SAL>10000’。这一转换由于减少了联接的数据量而大大提高了查询的执行性能。即便在这样一个非常简单的示例里,查询转换的益处和重要性也显而易见。

  复杂视图合并

  许多视图合并操作都是直截了当的,如以上示例。但是,较复杂的视图,如包含GROUP BY 或DISTINCT 操作符的视图合并起来就不那么容易了。Oracle 为合并这类复杂视图提供了一些高级技术。

  请看以下带有GROUP BY 语句的视图。在该示例中,视图计算每个部门的平均工资。

  CREATE VIEW AVG_SAL_VIEW AS SELECT DEPTNO, AVG(SAL) AVG_SAL_DEPT FROM EMP GROUP BY DEPTNO

  查询的目的是要找出Oakland 每个部门的平均工资:

  SELECT DEPT.NAME, AVG_SAL_DEPT FROM DEPT, AVG_SAL_VIEW WHERE DEPT.DEPTNO = AVG_SAL_VIEW.DEPTNO AND DEPT.LOC = 'OAKLAND'

  可以转换为:

  SELECT DEPT.NAME, AVG(SAL) FROM DEPT, EMP WHERE DEPT.DEPTNO = EMP.DEPTNO AND DEPT.LOC = 'OAKLAND' GROUP BY DEPT.ROWID, DEPT.NAME

  该特殊转换的执行性能优点立即显现:该转换把EMP 数据在分组聚合前进行联接和筛选,而不是在联接前将EMP 表的所有数据分组聚合。

  子查询“展平”

  Oracle 有一些转换能将不同类型的子查询转变为联接、半联接或反联接。作为该领域内的技术示例,我们来看下面这个查询,找出有工资超过10000 的员工的那些部门:

  SELECT D.DNAME FROM DEPT D WHERE D.DEPTNO IN (SELECT E.DEPTNO FROM EMP E WHERE E.SAL > 10000)

  存在一系列可以优化本查询的执行计划。Oracle 会考虑这些可能的不同转换,基于开销选出最佳计划。

  如果不进行任何转换,这一查询的执行计划如下:

  OPERATION OBJECT_NAME OPTIONS
  SELECT STATEMENT
  FILTER
  TABLE ACCESS DEPT FULL
  TABLE ACCESS EMP FULL

  按照该执行计划,将扫描DEPT 表的每一行查找所有满足子查询条件的EMP 记录。通常,这不是一种高效的执行策略。然而,查询转换可以实现效率更高的计划。

  该查询的可能计划之一是将查询作为“半联接”来执行。“半联接”是一种特殊类型的联接,它消除了联接中来自内表的冗余值(这实际上就是该子查询的原本的语义)。在该示例中,优化程序选择了一个散列半联接,尽管Oracle 也支持排序-合并以及嵌套-循环半联接:

  OPERATION OBJECT_NAME OPTIONS
  SELECT STATEMENT
  HASH JOIN SEMI
  TABLE ACCESS DEPT FULL
  TABLE ACCESS EMP FULL

  由于SQL 没有用于半联接的直接语法,此转换过的查询不能使用标准的SQL 来表示。但是,转换后的伪SQL 将是:

  SELECT DNAME FROM EMP E, DEPT D WHERE D.DEPTNO E.DEPTNO AND E.SAL > 10000;

  另一个可能的计划是优化程序可以决定将DEPT 表作为联接的内表。在这种情况下,查询作为通常的联接来执行,但对EMP 表进行特别排序,以消除冗余的部门号:

  OPERATION OBJECT_NAME OPTIONS
  SELECT STATEMENT
  HASH JOIN
  SORT UNIQUE
  TABLE ACCESS EMP FULL
  TABLE ACCESS DEPT FULL

  转换后的SQL 语句为:

  SELECT D.DNAME FROM (SELECT DISTINCT DEPTNO FROM EMP) E, DEPT D WHERE E.DEPTNO = D.DEPTNO AND E.SAL > 10000;

  与视图合并一样,子查询展平也是获得良好查询执行性能的基本优化办法。

  传递谓词生成

  在某些查询中,由于表间的联接关系,一个表中的谓词可以转化为另一个表中的谓词。Oracle 会以这种方式演绎出新的谓词,这类谓词被称为传递谓词。例如,来看一个查询,找出定货当天运出的所有商品:

  SELECT COUNT(DISTINCT O_ORDERKEY) FROM ORDER, LINEITEM WHERE O_ORDERKEY = L_ORDERKEY AND O_ORDERDATE = L_SHIPDATE AND O_ORDERDATE BETWEEN '1-JAN-2002' AND '31-JAN-2002'

  利用传递性,该ORDER 表中的谓词也可以用于LINEITEM 表:

  SELECT COUNT(DISTINCT O_ORDERKEY) FROM ORDER, LINEITEM WHERE
posted @ 2008-11-20 09:46 竹子 阅读(428) | 评论 (0)编辑 收藏
1、父子二人经过五星级饭店门口,看到一辆十分豪华的进口轿车。儿子不屑地对他的父亲说:「坐这种车的人,肚子里一定没有学问!」父亲则轻描淡写地回答:「说这种话的人,口袋里一定没有钱!」
    
    (注:你对事情的看法,是不是也反映出你内心真正的态度?)
    
    2、晚饭后,母亲和女儿一块儿洗碗盘,父亲和儿子在客厅看电视。突然,厨房里传来打破盘子的响声,然后一片沉寂。是儿子望着他父亲,说道:「一定是妈妈打破的。」「你怎么知道?」「她没有骂人。」
    
    (注:我们习惯以不同的标准来看人看己,以致往往是责人以严,待己以宽。)
    
    3、有两个台湾观光团到日本伊豆半岛旅游,路况很坏,到处都是坑洞。其中一位导游连声抱歉,说路面简直像麻子一样。说而另一个导游却诗意盎然地对游客说:诸位先生女士,我们现在走的这条道路,正是赫赫有名的伊豆迷人酒窝大道。」
    
    (注:虽是同样的情况,然而不同的意念,就会产生不同的态度。思想是何等奇妙的事,如何去想,决定权在你。)
    
    4、同样是小学三年级的学生,在作文中说他们将来的志愿是当小丑。中国的老师斥之为:「胸无大志,孺子不可教也!」而外国的老师则会说:「愿你把欢笑带给全世界!」
    
    (注:身为长辈的我们,不但容易要求多于鼓励,更狭窄的界定了成功的定义。)
    
    5、在故宫博物院中,有一个太太不耐烦地对她先生说:「我说你为甚么走得这么慢。原来你老是停下来看这些东西。」
    
    (注:有人只知道在人生的道路上狂奔,结果失去了观看两旁美丽花朵的机会。)
    
    6、妻子正在厨房炒菜。丈夫在她旁边一直唠叨不停:慢些。小心!火太大了。赶快把鱼翻过来。快铲起来,油放太多了!把豆腐整平一下!「哎呀!」妻子脱口而出,「我懂得怎样炒菜。」「你当然懂,太太,」丈夫平静地答道:「我只是要让你知道,我在开车时,你在旁边喋喋不休,我的感觉如何。」
    
    (注:学会体谅他人并不困难,只要你愿意认真地站在对方的角度和立场看问题。)
    
    7、一辆载满乘客的公共汽车沿着下坡路快速前进着,有一个人後面紧紧地追赶着这辆车子。一个乘客从车窗中伸出头来对追车子的人说:“老兄!算啦,你追不上的!”“我必须追上它,”这人气喘吁吁地说:“我是这辆车的司机!”
    
    (注:有些人必须非常认真努力,因为不这样的话,後果就十分悲惨了!然而也正因为必须全力以赴,潜在的本能和不为人知的特质终将充份展现出来。)
    
    8、甲:「新搬来的邻居好可恶,昨天晚上三更半夜、夜深人静之时然跑来猛按我家的门铃。」
    
     乙:「的确可恶!你有没有马上报警?」
    
     甲:「没有。我当他们是疯子,继续吹我的小喇叭。」
    
    (事出必有因,如果能先看到自己的不是,答案就会不一样在你面对冲突和争执时,先想一想是否心中有亏,或许很快就能释怀了)
    
    9、某日,张三在山间小路开车,正当他悠哉地欣赏美丽风景时,突然迎面开来一辆货车,而且满囗黑牙的司机还摇下窗户对他大骂一声:“猪!”
    
    张三越想越纳闷,也越想越气,於是他也摇下车窗回头大骂:“你才是猪!”
    
    才刚骂完,他便迎头撞上一群过马路的猪。
    
      (不要错误的诠释别人的好意,那只会让自己吃亏,并且使别人受辱。在不明所以之前,先学会按捺情绪,耐心观察,以免事後生发悔意。)
    
    10、小男孩问爸爸:“是不是做父亲的总比做儿子的知道得多?”
    
    爸爸回答:“当然啦!”
    
    小男孩问:“电灯是谁发明的?”
    
    爸爸:“是爱迪生。”
    
    小男孩又问:“那爱迪生的爸爸怎麽没有发明电灯?”
    
    (很奇怪,喜欢倚老卖老的人,特别容易栽跟斗。权威往往只是一个经不起考验的空壳子,尤其在现今这个多元开放的时代。)
    
    11、小明洗澡时不小心吞下一小块肥皂,他的妈妈慌慌张张地打电话向家庭医生求助。医生说:“我现在还有几个病人在,可能要半小时後才能赶过去。”
    
    小明妈妈说:“在你来之前,我该做甚麽?”
    
    医生说:“给小明喝一杯白开水,然後用力跳一跳,你就可以让小明用嘴巴吹泡泡消磨时间了。”
    
    (take it easy,放轻松放轻松些,生活何必太紧张?事情既然已经发生了,何不坦然自在的面对。担心不如宽心,穷紧张不如穷开心。)
    
    12、一把坚实的大锁挂在大门上,一根铁杆费了九牛二虎之力,还是无法将它撬开。钥匙来了,他瘦小的身子钻进锁孔,只轻轻一转,大锁就“啪”地一声打开了。
    
    铁杆奇怪地问:“为什麽我费了那麽大力气也打不开,而你却轻而易举地就把它打开了呢?”
    
    钥匙说:“因为我最了解他的心。” 

问题一
如果你家附近有一家餐厅,东西又贵又难吃,桌上还爬着蟑螂,你会因为它很近很方便,就一而再、再而三地光临吗?
回答:你一定会说,这是什么烂问题,谁那么笨,花钱买罪受?
可同样的情况换个场合,自己或许就做类似的蠢事。不少男女都曾经抱怨过他们的情人或配偶品性不端,三心二意,不负责任。明知在一起没什么好的结果,怨恨已经比爱还多,但却不知道为什么还是要和他搅和下去,分不了手。说穿了,只是为了不甘,为了习惯,这不也和光临餐厅一样?
――做人,为什么要过于执著?!
问题二
如果你不小心丢掉100块钱,只知道它好像丢在某个你走过的地方,你会花200块钱的车费去把那100块找回来吗?
回答:一个超级愚蠢的问题。
可是,相似的事情却在人生中不断发生。做错了一件事,明知自己有问题,却死也不肯认错,反而花加倍的时间来找藉口,让别人对自己的印象大打折扣。被人骂了一句话,却花了无数时间难过,道理相同。为一件事情发火,不惜损人不利已,不惜血本,不惜时间,只为报复,不也一样无聊?
失去一个人的感情,明知一切已无法挽回,却还是那么伤心,而且一伤心就是好几年,还要借酒浇愁,形销骨立。其实这样一点用也没有,只是损失更多。
――做人,干吗为难自己?!
问题三
你会因为打开报纸发现每天都有车祸,就不敢出门吗?
回答:这是个什么烂问题?当然不会,那叫因噎废食。
然而,有不少人却曾说:现在的离婚率那么高,让我都不敢谈恋爱了。说得还挺理所当然。也有不少女人看到有关的诸多报道,就对自己的另一半忧心忡忡,这不也是类似的反应?
所谓乐观,就是得相信:虽然道路多艰险,我还是那个会平安过马路的人,只要我小心一点,不必害怕过马路。
――做人,先要相信自己。
问题四
你相信每个人随便都可以成功立业吗?
回答:当然不会相信。
但据观察,有人总是在听完成功人士绞尽脑汁的建议,比如说,多读书,多练习之后,问了另一个问题?那不是很难?
我们都想在3分钟内学好英文,在5分钟内解决所有难题,难道成功是那么容易的吗?改变当然是难的。成功只因不怕困难,所以才能出类拔萃。
有一次坐在出租车上,听见司机看到自己前后都是高档车,兀自感叹:唉,为什么别人那么有钱,我的钱这么难赚?我心血来潮,问他:你认为世上有什么钱是好赚的?他答不出来,过了半晌才说:好像都是别人的钱比较好赚。
其实任何一个成功者都是艰辛取得。我们实在不该抱怨命运。
――做人,依靠自己!
问题五
你认为完全没有打过篮球的人,可以当很好的篮球教练吗?
回答:当然不可能,外行不可能领导内行。
可是,有许多人,对某个行业完全不了解,只听到那个行业好赚钱,就马上开起业来了。
我看过对穿着没有任何口味、或根本不在乎穿着的人,梦想却是开间服装店;不知道电脑怎么开机的人,却想在网上赚钱,结果道听途说,却不反省自己是否专业能力不足,只抱怨时不我与。
――做人,量力而行。
问题六
相似但不相同的问题:你是否认为,篮球教练不上篮球场,闭着眼睛也可以主导一场完美的利?
回答:有病啊,当然是不可能的。
可是却有不少朋友,自己没有时间打理,却拼命投资去开咖啡馆,开餐厅,开自己根本不懂的公司,火烧一样急着把辛苦积攒的积蓄花掉,去当一个稀里糊涂的投资人。亏的总是比赚的多,却觉得自己是因为运气不好,而不是想法出了问题。
――做人,记得反省自己。
问题七
你宁可永远后悔,也不愿意试一试自己能否转败为胜?
解答:恐怕没有人会说:对,我就是这样的孬种吧。
然而,我们却常常在不该打退堂鼓时拼命打退堂鼓,为了恐惧失败而不敢尝试成功。
以关颖珊赢得2000年世界花样滑冰冠军时的精彩表现为例:她一心想赢得第一名,然而在最后一场比赛前,她的总积分只排名第三位,在最后的自选曲项目上,她选择了突破,而不是少出错。在4分钟的长曲中,结合了最高难度的三周跳,并且还大胆地连跳了两次。她也可能会败得很难看,但是她毕竟成功了。
她说:因为我不想等到失败,才后悔自己还有潜力没发挥。
一个中国伟人曾说;胜利的希望和有利情况的恢复,往往产生于再坚持一下的努力之中。
――做人,何妨放手一搏。
问题八
你的时间无限,长生不老,所以最想做的事,应该无限延期?
回答:不,傻瓜才会这样认为。
然而我们却常说,等我老了,要去环游世界;等我退休,就要去做想做的事情;等孩子长大了,我就可以……
我们都以为自己有无限的时间与精力。其实我们可以一步一步实现理想,不必在等待中徒耗生命。如果现在就能一步一步努力接近,我们就不会活了半生,却出现自己最不想看到的结局。
――做人,要活在当下。

posted @ 2008-09-11 21:01 竹子 阅读(175) | 评论 (0)编辑 收藏