EXISTS 执行顺序

 

select * from a where a.s_status=1 and exists (select orderid from b on a.orderid=b.orderid)

exists执行顺序

1.首先exists 返回的是true或false

2.查询一条a的数据,会去执行exists 若返回true则存在结果集中,再执行a的下一条数据,直到a的数据执行完

3.exists 里的数据是怎么执行的呢?只要满足条件就会返回true,没必要把b表中的数据都查询一遍

CLR-2-2-引用类型和值类型

 

引用类型和值类型,是一个老生常谈的问题了。装箱拆箱相信也是猿猿都知,但是还是跟着CLR via C#加深下印象,看有没有什么更加根本和以前被忽略的知识点。

引用类型:

引用类型有哪些这里不过多赘述,来关心一下它在计算机内部的实际操作,引用类型总是从托管堆分配,线程栈上存储的是指向堆上数据的引用地址,首先确立一下四个事实:

内存必须从托管堆分配

堆上分配成员时,CLR要求你必须有一些额外成员(比如同步块索引,类型对象指针)。这些成员必须初始化。

对象中的其他字节总是设为零

从托管堆上分配对象时,可能强制执行一次垃圾回收

所以引用类型对性能是有显著影响的。

值类型:

值类型是CLR提供的轻量级类型,它把实际的字段存储在线程栈上

值类型不受垃圾回收器的限制,所以它的存在缓解了托管堆的压力,也减少了垃圾回收的次数。

值类型都是派生自System.ValueType

所有值类型都是隐式密封的,目的是防止将值类型作为其他引用类型的基类

值类型初始化为空时,默认为0,它不像引用类型是指针,它不会抛出NullReferenceException异常,CLR还为值类型提供了可控类型。

误区防范:根据我自己的经验,要避免对引用类型值类型赋值的错误认识,我们先需要清楚,定义值类型,引用类型的底层实际操作,下面先根据流程图了解一下:

   

例子:

 1 class SomeRef{public int x;}
 2 struct SomeVal{public int x;}
 3
 4 staic void Test
 5 {
 6 SomeRef  r1=new SomeRef();
 7 SomeVal v1 =new SomeVal();
 8
 9 r1.x=5;
10 v1.x=5;
11
12 SomeRef  r2=r1;
13 SomeVal v2 =v1;
14 r1.x=8;
15 v1.x=9;
16
17 string a="QWER";
18 string b=a;
19 a="TYUI";
20 }

这样类似的例子,相信只要讲到引用类型,值类型,就一定会见到,继续复习一下。

首先揭晓几轮复制后的结构:r1.x=8,r2.x=8 v1.x=9 v2.x=5 a="TYUI" b="QWER"

简单分析一下:

r1 ,r2在线程栈上存储的是同一个指向内存堆的地址,当r1值改变时,其实是直接改变内存堆里的内容,自然r1,r2全部变成了8。

而v1,v2是独立存储在线程栈上的,v1值改变时,只是单单改变v1线程栈里的值,自然v2=5,v1=9。

而a,b的值为什么不像上面r1.x一样变化呢,它们不是引用类型吗,这就需要去看看上面的流程图,因为你在给a改变赋值时,其实是在托管堆上开辟了一个新的空间,你传给a的是一个新的地址,而b还指向原来的老地址。

结合上面的三个图和示例,对于引用类型和值类型构建相信应该有一个清楚的理解了。

使用值类型的一些建议:

值类型相对于引用类型,性能上更有优势,但是考虑在业务上的问题,值类型一般需要满足下面的全部条件,才是适合定义为值类型:

类型具有基元类型的行为。也就是说,是十分简单的类型,没有成员会修改类型的任何实例。如果类型没有提供会更改其他字段的成员,就称为不可变类型(immutable)。事实上,对于许多值类型,我们都建议将全部字段标记为readonly

类型不需要从其他类型继承

类型不派生出其他类(隐式密封)。

类型大小也应考虑:

因为实参默认以传值方式传递,造成对值类型实例中的字段进行复制,如果值类型过于大会对性能造成损害。

同样,当顶一个值类型的方法返回时,实例中的字段会复制到调用者分配的内存,也可能造成性能的损害。

所以,必须满足以下任意条件:

类型实例较小(16字节或更小)

类型实例较大(大于16字节),但不作为方法实参传递,也不从方法传递

值类型的局限:

值类型有两种形式:未装箱和已装箱,而引用类型一直是已装箱。

值类型从System.ValueType派生,System.ValueType重写了Equals和GetHashCode方法。生成哈希码时,会将对象的实例字段的值考虑在内。所以定义自己的值类型时,因重写Equals和GetHashCode方法。

值类型不能被继承,它自己的方法不能是抽象的,所有都是隐式密封的。

值类型不在内存堆中分配,所以一个实例的方法不再活动时,分配给值类型的内存空间会被释放,而没有垃圾回收机制来处理它。

值类型的装箱拆箱:

例如,ArrayList不断的添加值类型进入数组时,就会发生不断的装箱操作,因为它的Add方法参数是object类型,自然装箱就不可避免,自然也会造成性能的损失(FCL现在提供了泛型集合类,System.Collection.Generic.List<T>,它不需要装箱拆箱操作。使得性能提升不少)。

装箱相关的含义相信不用过多解释,我们来关心一下,内存中的变化,看看它是如何对性能造成影响的。

装箱:

在托管堆中分配内存。内存大小时值类型各字段所需的内存加上两个额外成员(托管堆所有对象都有)类型对象指针和同步块索引所需的内存量。

值类型的字段值复制到堆内存的空间中。

返回堆上对应的地址

然后,一个值类型就变成了引用类型。

拆箱:

根据引用类型的地址找到堆内存上的值

将值复制给值类型

拆箱的代价比装箱小得多

装箱拆箱注意点:

下面通过几个示例,来熟悉一下装箱拆箱的过程,并学会如何避免错误的判定装箱拆箱,CLR via C#这两个实例对装箱拆箱的理解非常有帮助:

 1     internal struct Point : IComparable
 2     {
 3         private Int32 m_x,m_y;
 4         public Point(int x,int y)
 5         {
 6             m_x = x;
 7             m_y = y;
 8         }
 9
10         public override string ToString()
11         {
12             return String.Format("({0},{1})", m_x.ToString(), m_y.ToString());
13         }
14
15
16         public int CompareTo(Point p)
17         {
18             return Math.Sign(Math.Sqrt(m_x * m_x + m_y * m_y) - Math.Sqrt(p.m_x * p.m_x + p.m_y * p.m_y));
19         }
20
21         public int CompareTo(object obj)
22         {
23             if (GetType() != obj.GetType())
24             {
25                 throw new ArgumentException("o is not a point");
26             }
27            return CompareTo((Point)obj);
28         }
29     }
 1         static void Main(string[] args)
 2         {
 3             //在栈上创建两个实例
 4             Point p1 = new Point(10,10);
 5             Point p2 = new Point(10,20);
 6
 7             //调用Tostring不装箱
 8             Console.WriteLine(p1.ToString());
 9
10             //调用非虚方法GetType装箱
11             Console.WriteLine(p1.GetType());
12
13             //调用CompareTo,不装箱
14             Console.WriteLine(p1.CompareTo(p2));
15
16             //p1装箱
17             IComparable C = p1;
18             Console.WriteLine(C.GetType());
19
20             //不装箱,调用的CompareTo(object)
21             Console.WriteLine(p1.CompareTo(C));
22
23              //不装箱,调用的CompareTo(object)
24             Console.WriteLine(p1.CompareTo(p2));
26
27             Console.ReadKey();
28         }

1.调用ToString

不装箱,因为ToString是从ValueType继承的虚方法,中间没有类型转换的发生,不需要进行装箱,另外注意的是:Equals,GetHashCode,ToString都是从ValueTye继承的虚方法,由于值类型都是密封类,无法派生,所以只要你的值类型重写了这些方法,并没有去调用基类的实现,那么是不会发生装箱的,如果你去调用基类的实现,或者你没有实现这些方法,那么还是可能发生装箱。

2.调用GetType

GetType是继承自Object,并且不能被重写,所以无论如何值类型对其调用都会发生装箱,另外MemberwiseClone方法也是如此。

3.第一次调用CompareTo方法

因为Point里面有了类型为Point的参数CompareTo方法,不会发生装箱操作

4.p1转换为ICompable

确认过眼神,这一定是一个装箱。

5.第二次调用CompareTo方法

虽然这次调用的是参数为object的方法,但是注意的是:首先我们Point实现了这个重载,另外传进去的是个ICompable,自然不会发生装箱(另外,如果Point本身没有这个方法呢?当然会装箱,因为它不得不去调用父类的方法,而父类是一个引用类型,自然需要进行一次装箱操作)

6.第三次调用CompareTo方法

c是ICompable,而ICompable在托管堆上也有对应的方法,也不会有装箱发生。

 5  internal struct point
 6   {
 7         private int m_x,m_y;
 8
 9         pulic point(int x,int y)
10       {
11           m_x=x;
12           m_y=y;
13       }
14
15      public void change(int x,int y)
16     {
17          m_x=x;
18          m_y=y;
19     }
20
21     public ovveride String ToString()
22      {
23          return String.Format("{0},{1}",m_x.ToString.m_y.ToString());
24      }
25
26  }  
 1 public static void Main()
 2 {
 3   Point p = new Point(1,1);
 4   Console.WriteLine(p);
 5
 6   p.Change(2,2);
 7   Console.WriteLine(p);
 8
 9   Object o=p;
10   Console.WriteLine(o);
11
12   ((Point) o).Change(3,3);
13   Console.WriteLine(o);
14 }

结果:当然是 (1,1)(2,2) (2,2) (2,2) 前面三次的结果很好理解,第四次为什么是(2,2),因为object没有change方法,它等拆箱拆到线程栈新的地址上,于是后面的操作则是在线程栈上进行,对o堆上的内容没有任何影响

 1      internale interface IChangeBoxedPoint
 2      {
 3           void Change(int x,int y);
 4      }
 5    internal struct point
 6     {
 7           private int m_x,m_y;
 8
 9           pulic point(int x,int y)
10       {
11            m_x=x;
12            m_y=y;
13        }
14
15       public void change(int x,int y)
16      {
17           m_x=x;
18           m_y=y;
19      }
20
21      public ovveride String ToString()
22       {
23           return String.Format("{0},{1}",m_x.ToString.m_y.ToString());
24       }
25
26   }  
 1 public static void Main()
 2 {
 3    Point p =new p(1,1);
 4    Console.WriteLine(p);
 5
 6    p.Change(2,2);
 7    Console.WriteLine(p);
 8
 9    Objec o =p;
10    Console.WriteLine(o);
11
12   ((Point) o).Change(3,3);
13   Console.WriteLine(o);
14
15   ((IChangeBoxedPoint) p).Change(4,4);
16   Console.WriteLine(p);
17
18   ((IChangeBoxedPoint) o).Change(5,5);
19   Console.WriteLine(o);
20 }

结果:前面四次的结果应该是显而易见了,(1,1)(2,2) (2,2) (2,2),那么第五次呢,来简单分析一下p装箱为IChangeBoxedPoint,然后把堆上对应的p的m_x,m_y改为4,4,但是对p输出时堆上的内容不仅回收了,而且输出的是原来p线程栈上的内筒,仍然还是刚刚的(2,2),第六步,o没有任何装箱拆箱操作,当然是预期的(5,5)

EXISTS 执行顺序 CLR-2-2-引用类型和值类型的更多相关文章

  1. [CLR via C#]引用类型和值类型

    一.引用类型与值类型的区别 CLR支持两种类型:引用类型和值类型.引用类型总是从托管堆上分配的,C#的new操作符会返回对象的内存地址.使用引用类型时,必须注意到一些性能问题. 1)内存必须从托管堆上 ...

  2. EXISTS 执行顺序

    select * from a where a.s_status=1 and exists (select orderid from b where a.orderid=b.orderid) exis ...

  3. CLR via C#深解笔记三 - 基元类型、引用类型和值类型 | 类型和成员基础 | 常量和字段

    编程语言的基元类型   某些数据类型如此常用,以至于许多编译器允许代码以简化的语法来操纵它们. System.Int32 a = new System.Int32();  // a = 0 a = 1 ...

  4. 重温CLR(四)基元类型、引用类型、值类型

    编程语言的基元类型 编译器直接支持的数据类型称为基元类型(primitive type).基元类型直接映射到framework类型(fcl)中存在的类型. 下表列出fcl类型 从另一个角度,可以认为C ...

  5. 《CLR via C#》读书笔记--基元类型、引用类型和值类型

    编程语言的基元类型 编译器直接支持的数据类型称为基元类型.基元类型直接映射到Framework类库中存在的类型.例如:C#中的int直接映射到System.Int32类型.下表给出了C#基元类型与对应 ...

  6. 《CLR via C#》读书笔记(5)基元类型、引用类型和值类型

    5.1 基元类型 编译器直接支持的数据类型称为基元类型(primitive type). 以下4行到吗生成完全相同的IL int a = 0; //最方便的语法 System.Int32 b = 0; ...

  7. 【CLR Via C#】第5章 基元类型、引用类型、值类型

    第二遍看这本书,决定记录一下加深印象. 1,基元类型 什么事基元类型?基元类型是直接映射到FrameWork类库(FCL)中存在的类型,编译器直接支持的数据类型.比如int直接映射到System.In ...

  8. [CLR via C#]5.2 引用类型和值类型

    原文:[CLR via C#]5.2 引用类型和值类型 CLR支持两种类型:引用类型和值类型. 虽然FCL中大多数都是引用类型,但开发人员用的最多的还是值类型.引用类型总是在托管堆上分配的,C#的ne ...

  9. CLR via C#读书日记一' 引用类型和值类型'

    CLR支持两种类型:引用类型和值类型. 引用类型总是在托管堆上分配的,C#的new操作符会返回对象的内存地址——也就是指向对象数据的内存地址. 使用引用类型必须注意到一些问题: 1)内存必须从托管堆上 ...

随机推荐

  1. laravel学习:容器绑定与解析

    1.在服务容器中注册类(bind) $this->app->bind('sender','MailSender');//$this->app成为服务容器.   2.从服务容器生成类( ...

  2. PowerDesigner 操作手册

    1.错误信息:Generation aborted due to errors detected during the verification of the model 解决方案: 把检查模型的选项 ...

  3. 离线缓存 application cache

    1. 什么是离线缓存: 离线缓存可以将站点的一些文件缓存到本地,它是浏览器自己的一种机制,将需要的文件缓存下来,以便后期即使没有连接网络,被缓存的页面也可以展示. 例子:比如我们在手机或电脑上访问一个 ...

  4. 二、spring中装配bean

    在spring框架中提供了三种 bean的装配方式,当然这三种装配方式是可以灵活的进行组合使用的,项目中使用最多的是自动装配bean的方式,也就是通过注解的方式进行bean的装配,一下是四种装配方式的 ...

  5. 获取本地验证码cookie

    window.document.onkeydown = function (evt) { evt = (evt) ? evt : window.event; if (evt.keyCode) { if ...

  6. 全国绿色计算大赛 模拟赛第二阶段 (Python)

    第1关气温预测 def dailyTemps(temp_list): result = [] for ca in range(0, len(temp_list)-1): for i in range( ...

  7. vue-cli webpack 快速搭建项目

    一.安装vue npm install vue -g 二.用vue-cli快速搭建项目 //全局安装vue-cli npm install install -g vue-cli //创建一个基于web ...

  8. 02--Activiti初始化表

    初始化数据库 方法一:执行sql脚本文件activiti-5.13\database\create\activiti.mysql.create.*.sql文件 方法二:代码创建(有流程自然就有表) p ...

  9. Qt 编写应用支持多语言版本--一个GUI应用示例

    简介 上一篇博文已经说过如何编写支持多语言的Qt 命令行应用,这一篇说说Qt GUI 应用多语言支持的坑. 本人喜欢用代码来写布局,而不是用 Qt Designer 来设计布局,手写布局比 Qt De ...

  10. 杭电 1789 Doing Homework again (贪心 求最少扣分)

    Description zichen has just come back school from the 30th ACM/ ICPC. Now he has a lot of homework t ...