[轉]通过DNS的负载均衡方案Round-robin DNS

From : http://haka.sharera.com/blog/BlogTopic/5967.htm

循环复用DNS负载均衡技术

循环DNS(Round-robin DNS)技术是负载平衡最常用的方法之一。最早的负载均衡技术是通过DNS服务中的随机名字解析来实现的。在DNS服务器中,可以为多个不同的地址配置同一个名字,这个数据被发送给其他名字服务器,而最终查询这个名字的客户机将在解析这个名字时随机使用其中一个地址。因此,对于同一个名字,不同的客户机会得到不同的地址,因此不同的客户访问的也就是不同地址的Web服务器,从而达到负载均衡的目的。

例如,如果希望使用三个Web服务器来回应对www.cqcc.com的HTTP请求,设它们的IP地址分别是:202.192.99.1,202.192.99.2,202.192.99.3。安装一个循环复用DNS软件,配置这个软件使得每次要求解析www.cqcc.com时返回所有三个IP地址。第一次解析结果中返回地址的次序与前面列出的相同,下一次请求则得到稍微不同的答案:202.192.99.2,202.192.99.3,202.192.99.1。再下一次则得到第三个答案:202.192.99.3,202.192.99.1,202.192.99.2。第一个客户将同202.192.99.1建立连接,因为202.192.99.1是它所看到的第一个IP地址。第二个客户看到的第一个IP地址是202.192.99.2,因此它将访问202.192.99.2。同样,第三个客户将访问202.192.99.3……

针对上面例子,可以设置该域的DNS服务器中关于该域的数据至少包括与下面例子类似的结果:

www1 IN A 202.192.99.1

www2 IN A 202.192.99.2

www3 IN A 202.192.99.3

www IN CNAME www1

www IN CNAME www2

www IN CNAME www3

这里先为每个计算机定义一个真实名字(www1、www2、www3),然后再为它们定义同一个别名。可以直接针对不同地址设置同一个真实名字(A记录),只是使用别名的方法易于管理一些。

由于此时反向解析只能针对一台计算机,那么每个Web服务器都需要使用ServerName重新定义同一个名字,或者设置名字解析的顺序为hosts文件优先,并在hosts文件中定义本身为www,以保证每个服务器的名字设置保持一致。

循环DNS具有对客户机和服务器透明的优点。在事务处理开始时,它也只执行一次。但是,循环DNS常常不能成功,因为中间名服务器和客户机软件(包括应用很广的浏览器)常常将DNS返回的IP地址存储起来,或忽略存在时间(TTL)值。TTL是一位IP数据比特位,用来指示IP数据报在被丢弃前可以转发到其它路由器的时间长度。

由于IP地址存储的原因,DNS服务器提供的负载平衡功能被绕过去了,客户机继续使用被存储起来的IP地址,而不去进行重新连接。这就产生了一个“热点”,在这个“热点”上,过度使用的服务器继续接收额外的接入。

DNS负载均衡的另一个问题是一旦某个服务器出现故障,即使及时修改了DNS设置,还是要等待足够的时间(刷新时间)才能发挥作用,而DNS服务器并不知道这一点,因此客户请求将被延迟,或返回一个“无法访问服务器”消息给用户,在此期间保存了故障服务器地址的客户计算机将不能正常访问服务器。

由于DNS数据是具备一个刷新时间的标志的,一旦超过这个时间限制过期,其他DNS服务器就需要和这个服务器交谈以重新获得地址数据。如果刷新时间较短,不同地方的DNS服务器能更新对应的地址,使出现故障的服务器地址可以及时删除,用户仍旧可以被引导到正常的服务器上,但如果用户缓冲了故障服务器的IP地址,这种方法也不能解决问题。同时将过期时间设置的过低将使DNS流量大增,而造成额外的网络问题。

由于循环DNS没有区分端口的能力,不能意识到服务器的可用性并且不能考虑服务器上的现有负载,无法对服务器负载进行动态地分析从而使得下一个请求总是由负载最小的服务器处理,因此循环复用DNS还有太多的限制,只能算是一种勉强可接受的负载平衡方案。

尽管存在多种问题,然而它还是一种非常有效的做法,当前使用在包括Yahoo在内的很多Web站点上。

From : http://www.maiun.com/2011/04/21/Round-robin-DNS.html

循环复用DNS负载均衡技术(Round-robin DNS)

循环DNS(Round-robin DNS)技术是负载平衡最常用的方法之一。最早的负载均衡技术是通过DNS服务中的随机名字解析来实现的。在DNS服务器中,可以为多个不同的地址配置同一个名字,这个数据被发送给其他名字服务器,而最终查询这个名字的客户机将在解析这个名字时随机使用其中一个地址。因此,对于同一个名字,不同的客户机会得到不同的地址,因此不同的客户访问的也就是不同地址的Web服务器,从而达到负载均衡的目的。

例如,如果希望使用三个Web服务器来回应对www.nuxnu.com的HTTP请求,设它们的IP地址分别是:202.192.99.1,202.192.99.2,202.192.99.3。安装一个循环复用DNS软件,配置这个软件使得每次要求解析www.nuxnu.com时返回所有三个IP地址。第一次解析结果中返回地址的次序与前面列出的相同,下一次请求则得到稍微不同的答案:202.192.99.2,202.192.99.3,202.192.99.1。再下一次则得到第三个答案:202.192.99.3,202.192.99.1,202.192.99.2。第一个客户将同202.192.99.1建立连接,因为202.192.99.1是它所看到的第一个IP地址。第二个客户看到的第一个IP地址是202.192.99.2,因此它将访问202.192.99.2。同样,第三个客户将访问202.192.99.3

针对上面例子,可以设置该域的DNS服务器中关于该域的数据至少包括与下面例子类似的结果:

www1 IN A 202.192.99.1

www2 IN A 202.192.99.2

www3 IN A 202.192.99.3

www IN CNAME www1

www IN CNAME www2

www IN CNAME www3

这里先为每个计算机定义一个真实名字(www1、www2、www3),然后再为它们定义同一个别名。可以直接针对不同地址设置同一个真实名字(A记录),只是使用别名的方法易于管理一些。

由于此时反向解析只能针对一台计算机,那么每个Web服务器都需要使用ServerName重新定义同一个名字,或者设置名字解析的顺序为hosts文件优先,并在hosts文件中定义本身为www,以保证每个服务器的名字设置保持一致。

循环DNS具有对客户机和服务器透明的优点。在事务处理开始时,它也只执行一次。但是,循环DNS常常不能成功,因为中间名服务器和客户机软件(包括应用很广的浏览器)常常将DNS返回的IP地址存储起来,或忽略存在时间(TTL)值。TTL是一位IP数据比特位,用来指示IP数据报在被丢弃前可以转发到其它路由器的时间长度。

由于IP地址存储的原因,DNS服务器提供的负载平衡功能被绕过去了,客户机继续使用被存储起来的IP地址,而不去进行重新连接。这就产生了一个“热点”,在这个“热点”上,过度使用的服务器继续接收额外的接入。

DNS负载均衡的另一个问题是一旦某个服务器出现故障,即使及时修改了DNS设置,还是要等待足够的时间(刷新时间)才能发挥作用,而DNS服务器并不知道这一点,因此客户请求将被延迟,或返回一个“无法访问服务器”消息给用户,在此期间保存了故障服务器地址的客户计算机将不能正常访问服务器。

由于DNS数据是具备一个刷新时间的标志的,一旦超过这个时间限制过期,其他DNS服务器就需要和这个服务器交谈以重新获得地址数据。如果刷新时间较短,不同地方的DNS服务器能更新对应的地址,使出现故障的服务器地址可以及时删除,用户仍旧可以被引导到正常的服务器上,但如果用户缓冲了故障服务器的IP地址,这种方法也不能解决问题。同时将过期时间设置的过低将使DNS流量大增,而造成额外的网络问题。

由于循环DNS没有区分端口的能力,不能意识到服务器的可用性并且不能考虑服务器上的现有负载,无法对服务器负载进行动态地分析从而使得下一个请求总是由负载最小的服务器处理,因此循环复用DNS还有太多的限制,只能算是一种勉强可接受的负载平衡方案。

 

配置循环复用

循环复用是 DNS 服务器用于共享和分配网络资源负载的本地平衡机制。如果发现主机名的多个 A RR,则可用它循环使用包含在查询应答中的主机 (A) 资源记录 (RR)。
在默认情况下,DNS 服务器的服务使用循环复用对资源记录进行排序,这些资源记录是在解析为多个映射 RR 的主机名应答中返回的。该功能提供了一种非常简便的方法,用于对客户机使用 Web 服务器和其他频繁查询的多宿主计算机的负载平衡。
要使循环复用正常工作,必须首先在该区域中注册所查询名称的多个 A RR。如果 DNS 服务器禁用循环复用,那么这些查询的响应顺序以应答列表中 RR 在区域(或者是它的区域文件,或者是 Active Directory)中存储时的静态排序为基础。
范例:循环复用
正向搜索型查询(对于所有匹配 DNS 域名的 A RR)用于有三个 IP 地址的多宿主计算机 (multihomed.example.microsoft.com)。独立的 A RR 用于将主机名映射到区域中的每个 IP 地址中。在存储的 example.microsoft.com 区域中,RR 以如下固定顺序显示:

multihomed IN A 10.0.0.2
multihomed IN A 10.0.0.3
multihomed IN A 10.0.0.1

查询服务器以解析该主机名的第一个 DNS 客户机以默认顺序接收列表。第二个客户机发送后续查询以解析该名称时,该列表将按以下方式循环使用:

multihomed IN A 10.0.0.2
multihomed IN A 10.0.0.3
multihomed IN A 10.0.0.1

注意
本地子网优先级取代了多宿主名称的循环复用。但是在启用时,循环复用仍然是对多个 RR 进行排序的辅助方法,这些 RR 是在作为地址 (A) 查询响应一部分的应答列表中返回的
区分本地子网的优先级
在默认情况下,当客户机查询解析为映射到多个 IP 地址的主机名时,DNS 服务使用本地子网优先排序作为给出同一网络上首选 IP 地址的方法。此功能要求客户应用程序尝试使用连接可用的最近(一般是最快的)IP 地址连接至主机。
DNS 服务按以下方式使用本地子网优先级:
DNS 服务确定是否需要本地子网的优先级排序查询响应。
如果有多个 A 资源记录 (RR) 与要查询的主机名匹配,则 DNS 服务可按其子网位置重新对记录进行排序。如果查询的主机名只与一个 A 资源记录匹配,或者客户机的 IP 网络地址与多重 RR 响应列表上的任何映射地址的 IP 网络地址匹配,则不需要进行优先排列。
对于匹配响应列表中的每一个 RR,DNS 服务决定了哪些记录(如果有)与查询客户机的子网位置匹配。
DNS 服务重新对响应列表进行排序,以便将与发出请求的客户机的本地子网匹配的 A RR 排在响应列表中的第一位。
按子网的顺序进行优先级排序后,响应列表将返回给发出请求的客户机。
简单范例:本地网络的优先排序
多宿主计算机 multihomed.example.microsoft.com,在 example.microsoft.com 区域中有三个主机 IP 地址相互分开的 A RR。单独的 A RR 用于每个主机的地址,该地址以如下顺序出现在区域中:

multihomed IN A 192.168.1.27
multihomed IN A 10.0.0.14
multihomed IN A 172.16.20.4

如果在 IP 地址 10.4.3.2 上的 DNS 客户机解析程序向服务器查询主机 multihomed.example.microsoft.com 的 IP 地址,则 DNS 服务将记录客户机的源 IP 网络地址 (10.0.0.0) 与 RR 响应列表中 10.0.0.4 地址的网络(类型 A)部分匹配。但是,DNS 服务按如下方式重新排序响应中的地址:

multihomed IN A 10.0.0.14
multihomed IN A 192.168.1.27
multihomed IN A 172.16.20.4

如果发出请求的客户机的 IP 地址没有与响应列表中任何 RR 匹配的本地网络,在这个列表不进行按优先级的排序。
复杂范例:本地子网的优先排序
如果要在使用 IP 子网(非默认子网掩码)的网络上工作,那么只存在很少的差异。如果在网络部分有多个地址匹配,则匹配的地址将被进一步排序并且最接近匹配子网地址的 RR 排列在第一位。
例如,多宿主计算机 multihomed.example.microsoft.com,在 example.microsoft.com 区域有四个主机 IP 地址相互分开的 A RR。其中的两个 IP 地址不是本地网的。虽然另外两个 IP 地址共享公用的 IP 网络地址,但是,因为使用了 IP 子网,因此它们代表基于自定义(非默认)子网掩码值 255.255.248.0 的不同物理子网连接。这些 RR 的例子以下列顺序出现在区域中:

multihomed IN A 192.168.1.27
multihomed IN A 172.16.22.4
multihomed IN A 10.0.0.14
multihomed IN A 172.16.31.5

如果发出请求的客户机的 IP 地址是 172.16.22.8,则与客户机相同的 IP 网络(172.16.0.0 网络)匹配的两个 IP 地址从响应列表的顶端返回到客户机。但是,在该例中,地址 172.16.22.4 被置于地址 172.16.31.5 之前,因为它与沿客户机 IP 地址一直到 172.16.20.0 的子网地址相匹配。
由 DNS 服务返回的重新排序的响应列表应为:

multihomed IN A 172.16.22.4
multihomed IN A 172.16.31.5
multihomed IN A 192.168.1.27
multihomed IN A 10.0.0.14

注意
IP 子网通过使用网络上所有 IP 地址的自定义或非默认子网掩码值进行加强。详细信息,请参阅子网掩码。
本地子网优先级取代了多宿主名称的循环复用。但是在启用循环复用时,通过将循环复用作为排序响应列表的辅助方法,RR 继续得以循环使用
这两个功能的最大的用处就是负载平衡,最常用的方式就是这样的:
假设你现在有两台WEB服务器使用了相同的内容,一个在内网一个在外网,为了减少内网用户访问外网中的网络并为内网用户提供一个较高的速度,你希望在使用一个DNS的情况下能够做到内网用户在使用域名访问时访问的是内网服务器,外网用户在使用域名访问的是外网服务器.
使用Win2000DNS这一点就非常容易做到,只要为每个服务器在DNS中使用相同的主机名建立A记录并启用DNS的循环复用与启用本地子网优先级功能就可以了,DNS服务器自然为你做好引导工作。

 

负载均衡算法小结

互联网分布式系统中,很多服务是数据存储相关的,海量访问量下,直接访问存储介质是抗不住的,需要使用cache,cache集群的负载均衡算法就成为一个重要的话题,这里对现有的负载均衡算法进行一些总结。
BTW:虽然是Cache负载均衡算法小结,其实可以说是负载均衡算法小结,只是针对Cache应用场景罢了。

负载均衡算法主要有:
Static算法
Random算法
Round robin算法
Hash算法
CARP算法
Consistent hash算法

Static算法
负载均衡的石器时代,为一个服务指定多个IP:PORT,备份模式,其总是返回服务器组的第一个服务器(只要第一个服务器可用),当第一个服务器没有用的时候,才会返回后续可用的服务器。
这种情况下,每台机器都包括全量的数据,查询通常会落到第一台机器上,第一台机器上Cache命中率高,但是当失败的时候,落到第二胎机器上,那就杯具了,Cache命中率低!

Random算法
对于无状态服务比较适用,随便选取一台机器就可以。
idx=rand()%M
在实际使用中,跟Static算法一样,都是模块维护全量数据,这个还好每台机器的cache命中率理论上应该差不多,但是都不高,为啥呢?因为同样一个请求一会落到机器A,一会落到机器B上。败家子,浪费内存,内存有限,Cache会被淘汰,频繁淘汰,当然使得命中率低下。

Round robin算法
典型的平均主义,顺序依次选取服务器。
idx=(idx+1)%M
同样的模块维护全量数据,跟Random一样杯具,基本上一样的原因。相同的请求会被落到不同的机器上,导致Cache命中率低。

Hash算法
又叫取余算法,将query key做hash之后,按照机器数量取余,选取中一个机器进行连接服务。
idx=hash(query_key)%M
余数计算的方法简单,数据的分散性也相当优秀,但也有其缺点。那就是当添加或移除服务器时,缓存重组的代价相当巨大。添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而影响缓存的命中率。

CARP算法
CARP准确的说不是一个算法,而是一个协议,Cache Array Routing Protocol,Cache群组路由协议。
计算全部服务器的idx_key=hash(query_key+server_idx),其中计算得到idx_key最大的server_idx就是需要的idx。
假设开始3台后端服务器,请求用标志串 req = "abcd" 来标志,服务器用 S1, S2, S3来标志, 那么,通过对 req + Sx 合并起来计算签名就可以对每个服务器得到一个数值:
(req = "abcd" + S1) = K1
(req = "abcd" + S2) = K2
(req = "abcd" + S3) = K3
计算的方法可以使用crc,也可以使用MD5,目的的得到一个*散列*的数字,这样在K1,K2,K3中 必定有一个最大的数值,假设是K2,那么可以将请求req扔给S2,这样,以后对相同的请求, 相同的服务器组,计算出来的结果必定是K2最大,从而达到HASH分布的效果。
巧妙的地方在于,新增或者删除一台服务器的时候,不会引起已有服务器的cache大规模失效, 假设新增一台服务器S4,那么对S1,S2,S3计算的K值都完全相同,那么对S4可以计算得到一个新值K4,如果计算K的算法足够散列,那么原先计算到S1,S2,S3的请求,理论上都会有1/4的请求新计算得到的K4比原先的K大, 那么这1/4的请求会转移到S4,从而新增的S4服务器会负担1/4的请求,原先的S1,S2,S3也只会负担原先的3/4。

Consistent hash算法
一致性hash算法是:首先求出服务器(节点)的哈希值,并将其配置到0~2^32的圆(continuum)上。然后用同样的方法求出存储数据的键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上。如果超过2^32仍然找不到服务器,就会保存到第一台服务器上。
idx=FirstMaxServerIdx(hash(query_key))
consistent hash算法背后最基础的思想就是:对object和cache machine使用相同的hash函数【DHT算法的核心,P2P的理论基石,资源和地址节点在统一地址空间进行编址】。Consistent Hash适用于每个节点只保存部分数据,而不是像前面几种算法,每个节点保存全量数据。这样做的好处是能够把cache机器映射到一段interval上,而这段interval就会包含一定数目的对象的hash值。如果某台cache机器被移除了,那么它映射到的interval被和它相邻的一个cache机器托管,其他所有的cache机器都不用变。
一致性哈希算法最大程度的避免了key在服务节点列表上的重新分布,其他附带的改进就是有的一致性 哈希算法还增加了虚拟服务节点的方法,也就是一个服务节点在环上有多个映射点,这样就能抑制分布不均匀,最大限度地减小服务节点增减时的缓存重新分布。

转自:
http://blogold.chinaunix.net/u/12592/showart.php?id=2537201

参考:
http://icp.ircache.net/carp.txt
http://hi.baidu.com/fdwm_lx/blog/item/f670e73582c8411d90ef3950.html
http://blog.csdn.net/sparkliang/archive/2010/02/02/5279393.aspx

 

WHERE 1=1和WHERE 1=0的使用

where 1=1:

这是一种怎样的查询语句呢?首先说明,1=1不是查询语句中的任何关键词,所以,请您放心,不管你会不会使用这种语句,都没有任何关系,对于您而言,没有任何损失。
另外,众多网站都有select * from table where 1=1此类语句的介绍,并且,针对该类语句,讲得实在是让人越看越迷茫(一个抄袭一个的,简直不像话),不知道是在说什么,导致很多新手不得要领,从而对其耿耿于怀。
本文,专为您讲解该语句,阅读完此文,您就会拨开云雾、茅塞顿开。
我们先来看看这个语句的结果:select * from table where 1=1,其中where 1=1,由于1=1永远是成立的,返回TRUE,条件为真a所以,这条语句,就相当于select * from table,返回查询表中的所有数据。

一、不用where 1=1 在多条件查询中的困扰
举个例子,如果您做查询页面,并且,可查询的选项有多个,同时,还让用户自行选择并输入查询关键词,那么,按平时的查询语句的动态构造,代码大体如下:

string MySqlStr=”select * from table where”;

if(Age.Text.Lenght>0){
	MySqlStr=MySqlStr+“Age=“+“'Age.Text'“;
}
if(Address.Text.Lenght>0){
	MySqlStr=MySqlStr+“and Address=“+“'Address.Text'“;
}

假设一:
如果上述的两个IF判断语句,均为True,即用户都输入了查询词,那么,最终的MySqlStr动态构造语句变为:
MySqlStr=”select * from table where Age='18' and Address='地址啊'”
可以看得出来,这是一条完整的正确的SQL查询语句,能够正确的被执行,并根据数据库是否存在记录,返回数据。

假设二:
如果上述的两个IF判断语句不成立,那么,最终的MySqlStr动态构造语句变为:
MySqlStr=”select * from table where“
现在,我们来看一下这条语句,由于where关键词后面需要使用条件,但是这条语句根本就不存在条件,所以,该语句就是一条错误的语句,肯定不能被执行,不仅报错,同时还不会查询到任何数据。
上述的两种假设,代表了现实的应用,说明,语句的构造存在问题,不足以应付灵活多变的查询条件。

二、使用 where 1=1 的好处
假如我们将上述的语句改为:

string MySqlStr=”select * from table where  1=1 ”;

if(Age.Text.Lenght>0){
	MySqlStr=MySqlStr+“and Age=“+“'Age.Text'“;
}
if(Address.Text.Lenght>0){
	MySqlStr=MySqlStr+“and Address=“+“'Address.Text'“;
}

现在,也存在两种假设

假设一:
如果两个IF都成立,那么,语句变为:

MySqlStr=”select * from table where  1=1 and Age='18'  and Address='地址呢'”;

很明显,该语句是一条正确的语句,能够正确执行,如果数据库有记录,肯定会被查询到。
假设二:
如果两个IF都不成立,那么,语句变为:

MySqlStr=”select * from table where 1=1”;

现在,我们来看这条语句,由于where 1=1 是为True的语句,因此,该条语句语法正确,能够被正确执行,它的作用相当于:MySqlStr=”select * from table”,即返回表中所有数据。
言下之意就是:如果用户在多条件查询页面中,不选择任何字段、不输入任何关键词,那么,必将返回表中所有数据;如果用户在页面中,选择了部分字段并且输入了部分查询关键词,那么,就按用户设置的条件进行查询。
说到这里,不知道您是否已明白,其实,where 1=1的应用,不是什么高级的应用,也不是所谓的智能化的构造,仅仅只是为了满足多条件查询页面中不确定的各种因素而采用的一种构造一条正确能运行的动态SQL语句的一种方法。

三、必须使用 where 1=1 才能做多条件查询吗
非也,您爱使用就使用,您不喜欢使用就不使用,对于您而言,不损失什么,也不会多得什么;
那么,如果我不使用where 1=1做多条件查询,该如何构造动态查询语句呢?非常简单,在下给您提供一种思维:
如下语句:

string MySqlStr=”select * from table”;

if(Age.Text.Lenght>0){
	QuerySqlStr=QuerySqlStr+“Age=“+“'Age.Text'“;
}
if(Address.Text.Lenght>0){
	QuerySqlStr=QuerySqlStr+“and Address=“+“'Address.Text'“;
}
if(QuerySqlStr.Lenght>0){
	MySqlStr=MySqlStr+“ where “+QuerySqlStr;
}

不管你使用不使用where 1=1做多条件查询,只要您能够保证您构造出来的查询语句,是正确的就万无一失了。

四、where 1=1 的总结
为方便构造动态的多条件之不确定因素的复杂的正确的查询语句所采取的一种“江湖手段”。
此类方法,一般,在书籍上不常见,而在实际的应用中,人们得从现实角度考虑,即要保证能满足多条件查询、同时还要能应付不确定因素的灵活性,最后还要保证语句不出现任何语法错误。
该方法不失为一种好方法。

where 1=0:

这个条件始终为false,结果不会返回任何数据,只有表结构,可用于快速建表

"SELECT * FROM strName WHERE 1 = 0";

该select语句主要用于读取表的结构而不考虑表中的数据,这样节省了内存,因为可以不用保存结果集。

create table newtable as select * from oldtable where 1=0;

创建一个新表,而新表的结构与查询的表的结构是一样的。

 

You can't specify target table 'A' for update in FROM clause

mysql> UPDATE EACONTACTGROUPS A 

SET GROUPNAME=(SELECT CONCAT(B.GROUPNAME,'-',A.GROUPNAME) FROM EACONTACTGROUPS B WHERE B.CORPID=A.CORPID AND B.USERID=A.USERID AND B.GROUPID=A.PARENTGROUPID) 

WHERE A.PARENTGROUPID IS NOT NULL;
ERROR 1093 (HY000): You can't specify target table 'A' for update in FROM clause

上面是目前MYSQL5.0仍然有的限制,文档中说:

In general, you cannot modify a table and select from the same table in a subquery.

For example, this limitation applies to statements of the following forms:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);UPDATE t ... WHERE col = (SELECT ... FROM t ...);{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

Exception:

The preceding prohibition does not apply if you are using a subquery for the modified table in the FROM clause.

Example:

UPDATE t ... WHERE col = (SELECT (SELECT ... FROM t...) AS _t ...);

Here the prohibition does not apply because a subquery in the FROM clause is materialized as a temporary table, so the relevant rows in t have already been selected by the time the update to t takes place.

依据文档,改成下面的样子就行了:

mysql> UPDATE EACONTACTGROUPS A

SET GROUPNAME=(SELECT CONCAT(B.GROUPNAME,'-',A.GROUPNAME) FROM ( SELECT GROUPNAME,CORPID,USERID,GROUPID,PARENTGROUPID FROM EACONTACTGROUPS) B

WHERE B.CORPID=A.CORPID AND B.USERID=A.USERID AND B.GROUPID=A.PARENTGROUPID)

WHERE A.PARENTGROUPID IS NOT NULL;
Query OK, 16 rows affected (0.01 sec)

Rows matched: 16 Changed: 16 Warnings: 0

注:今天写一个删除语句时找到的一点资料,通过临时表,解决了一个简单的删除语句。

原句:

mysql> delete from menu_item  

where parent_id = (select menu_item_id from menu_item where menu_data like '%manageVendors%');

修改后:

mysql> delete from menu_item  

where parent_id = (select temp.menu_item_id from (select m.menu_item_id,m.menu_data from menu_item m) temp where temp.menu_data like '%manageVendors%');
mysql> update student join (select sno  from student where cname='') tmp_student using(sno) set student.sname='sb';

 

多表JOIN删除

需要指定删除那张表的数据,否则MySQL会Confused,如下正确:

mysql> DELETE e.* FROM EventLog e LEFT JOIN CustInfo c USING (CustID) WHERE c.CustID IS NOT NULL;

參考:
http://vbb.twftp.org/archive/index.php/t-5043.html
posted @ 2011-05-25 16:26  Athrun  阅读(1162)  评论(0编辑  收藏  举报