自由之子的什么的,什么

对提升Linux下固态硬盘使用率的探讨

固态硬盘(SSD)不是普通的硬盘。文件在固态硬盘中的处理方式与地普通硬盘中的方式完全不同,如果安装Linux不同版本时没有把这些差异考虑进去,就很难充分发挥固态硬盘的优势,而且很可能在使用一段时间后造成严重的性能下降。

修改默认的固态硬盘(SSD)柱面大小

提升Linux下固态硬盘的使用率,在安装Linux操作系统前就应该做相关工作。系统会先在磁盘上创建分区,通常创建的分区包含固定数量的柱面,而默认情况下,每个柱面由16065512个字节的扇区组成。

现在的问题是,当默认柱面空间大小被完全使用后,固态硬盘就不能发挥最佳性能。因为要固态硬盘读这个操作需要使用4KB的字节块,而固态硬盘控制器删除操作则需要512KB的字节块。问题是,有了通常用于Linux上的默认分区,分区的开始没必要也是一个4KB新分区的开始。结果,一次读取或写入操作也许需要SSD设备上的两个不同的区块,这也减缓了SSD磁盘的性能。

为了避免这种问题,可以采用fdisk方式来创建分区,配置三个选项来指定使用柱面及拍面大小。具体的命令如下:

fdisk -H 32 -C 32 –c

这确保了分区均衡的方式兼容SSD写入和删除区块。一些最新的Linux版本默认情况下已经考虑了这个问题,以FedoraCore 14为例,它的第一个分区都会自动以第2048个扇区为开始,这就意味着写入和删除字节区块始终在同一个柱面上。

配置固态硬盘(SSD)的Ext 4

接着需要关注的就是文件系统。想要优化文件系统删除字节区块的效率,就必须确保小于512K的文件分布在不同的删除字节区块上。要做到这一点,必须确保在创建可扩展文件系统时指定了需要使用的条带的宽度和幅度。这些值在页面中指定,默认大小为4KB.要创建一个最佳的可扩展文件系统,应该使用如下命令:

mkfs.ext4 -E stride=128,stripe-width=128 /dev/sda1

如果要修改现有的文件系统的参数,可以使用tune2fs实用程序:

tune2fs -E stride=128,stripe-width=128 /dev/sda1

配置固态硬盘(SSD)的I/O调度程序

优化的第三个部分涉及到I/O调度程序。该模块是一个决定如何处理I/O请求的核心组件。默认情况下就是非常公平的排队,对于普通的磁盘驱动器来说,这是很好的方案,但对于以期限调度为优势的固态硬盘来说,这并不是最好的。

如果你想在系统中对所有磁盘采用期限调度,可以在内核加载时把elevator=deadline这句话加入到系统引导管理器(GURB)中;如果你只是想针对某一个磁盘,就应该在rc.local文件中加入类似如下实例的一句话,那么每次当系统重启,期限调度就会应用到指定的磁盘。如下实例将会对/dev/sdb磁盘采用期限调度。

echo deadline >/sys/block/sda/queue/scheduler

 

清理固态硬盘(SSD)中的数据块

最后一个重要的步骤称为“清理”,该操作可以确保在删除文件后相应的数据块真正清空,然后在创建新的文件时才能有可用的数据块。如果没有清理操作,一旦数据块空间填满,固态硬盘的性能就会下降。如果使用丢弃挂载选项,当文件删除后,数据块也会被相应地清除,这样可以显着提高固态硬盘的性能。2.6.33 以上的内核已经支持清理操作。

启用清理功能,需要在固态硬盘的/etc/fstab配置中为挂载文件系统添加丢弃选项。示例中的命令为挂载的根逻辑卷启用了清理操作。

/dev/system/root/ext4 discard,errors=remount-ro,noatime 0 1

该命令同时也添加了Noatime选项,该选项保证了文件的访问时间不会因为每次读取而更新,从而降低对文件系统的写入次数。

在fasab配文件中完成对文件系统的这些修改后,重启计算机,或者通知文件系统重新读取其配置,然后使用/etc/fstab文件中包含的mount -o命令重新安装每个文件系统。

posted by admin in 服务器 and have No Comments

Xtrabackup安装及使用

简介:
Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品。
Xtrabackup有两个主要的工具:xtrabackup、innobackupex
(1)xtrabackup只能备份InnoDB和XtraDB两种数据表,而不能备份MyISAM数据表
(2)innobackupex-1.5.1则封装了xtrabackup,是一个脚本封装,所以能同时备份处理innodb和myisam,但在处理myisam时需要加一个读锁
(3)使用帮助:http://www.percona.com/docs/wiki/percona-xtrabackup:start

环境:CentOS 5.4,xtrabackup-1.6.tar.gz

1、首先从www.percona.com下载
wget http://www.percona.com/downloads/XtraBackup/XtraBackup-1.6/Linux/binary/i686/xtrabackup-1.6.tar.gz

由于1.6版本新推不久,官网中的文档都没有来的及更新完善,源码方式的安装文档也并不完整,三思也只能连蒙带猜,下列安装步骤有可能并非最佳安装方式,仅只是提供了一种,源码安装xtrabackup并使其可用的方式。

由于xtrabackup依赖libinnodb链接库,因此需要先编译InnoDB,而后再编译xtrabackup。要编译安装xtrabackup最简单的方式当然是使用提供的编译脚本,首先还是解压缩文件,并进入到安装目录:

    [root@rhel5u3 software]# tar xvfz xtrabackup-1.6.tar.gz 

    [root@rhel5u3 software]# cd xtrabackup-1.6

ll的话会看到目录有两mysql-5.1.56.tar.gz和mysql-5.5.10.tar.gz两个mysql源码包,正是这两个源码包占用了大量的空间。除此外还有一个innobackupex的perl脚本程序,该脚本可以直接执行,不过执行备份任何时会报:

    sh: xtrabackup_55: command not found 

    innobackupex: fatal error: no ’mysqld’ group in MySQL options

    innobackupex: fatal error: OR no ’datadir’ option in group ’mysqld’ in MySQL options

提示xtrabackup_55命令不存在,接下来就是要编译xtrabackup。

在解压缩目录下执行utils/build.sh,注意一定要在xtrabackup安装目录内执行,执行时要指定与之匹配的MySQL数据库版本。

    [root@rhel5u3 xtrabackup-1.6]# utils/build.sh 

    Build an xtrabackup binary against the specified InnoDB flavor.

     

    Usage: build.sh CODEBASE

    where CODEBASE can be one of the following values or aliases:

    innodb51_builtin | 5.1        build against built-in InnoDB in MySQL 5.1

    innodb55         | 5.5        build against InnoDB in MySQL 5.5

    xtradb51         | xtradb   build against Percona Server with XtraDB 5.1

    xtradb55         | xtradb55 build against Percona Server with XtraDB 5.5

三思安装的是mysql5.5,因此这里指定innodb55,执行命令如下:

    [root@rhel5u3 xtrabackup-1.6]# utils/build.sh innodb55

该脚本会根据指定的引擎版本,自动解压缩适当的MySQL源码包并进行编译,这是最简单的安装方式。

命令执行完成之后,xtrabackup就可以用了,一般默认编译后该文件保存在xtrabackup-1.6/mysql-5.5.10/storage/innobase/xtrabackup/目录下,当然也可以通过find命令查找xtrabackup的具体路径。

创建两个软链接,以方便调用XtraBackup命令执行备份:

    [root@rhel5u3 xtrabackup-1.6]# ln -s /data/software/xtrabackup-1.6/innobackupex /usr/local/mysql55/bin/innobackupex 

    [root@rhel5u3 xtrabackup-1.6]# ln -s /data/software/xtrabackup-1.6/mysql-5.5.10/storage/innobase/xtrabackup/xtrabackup_innodb55 /usr/local/mysql55/bin/xtrabackup_55

将mysql55的bin加载到path环境变量,当然这步多数情况下应该在安装mysql时做过了:

    [root@rhel5u3 xtrabackup-1.6]# export PATH=$PATH:/usr/local/mysql55/bin

至此,XtraBackup的源码安装就完成了,接下来就可以使用这些命令执行备份任务了。例如,调用xtrabackup命令执行备份,举个简单的备份示例如下:

    [root@rhel5u3 ~]# xtrabackup_55 –defaults-file=/data/mysqldata/3306/my.cnf –backup –target-dir=/data/mysql_20110524 

    xtrabackup_55  Ver undefined Rev undefined for 5.5.10 Linux (x86_64)

    xtrabackup: uses posix_fadvise().

    xtrabackup: cd to /data/mysqldata/3306/data

    xtrabackup: Target instance is assumed as followings.

    xtrabackup:   innodb_data_home_dir = /data/mysqldata/3306/innodb_ts

    xtrabackup:   innodb_data_file_path = ibdata1:10M:autoextend

    xtrabackup:   innodb_log_group_home_dir = /data/mysqldata/3306/innodb_log

    xtrabackup:   innodb_log_files_in_group = 2

    xtrabackup:   innodb_log_file_size = 5242880

    110524 17:31:16 InnoDB: Using Linux native AIO

    >> log scanned up to (1598402)

    [01] Copying /data/mysqldata/3306/innodb_ts/ibdata1

    to /data/mysql_20110524/ibdata1

    [01]        …done

    xtrabackup: The latest check point (for incremental): ’1598402′

    >> log scanned up to (1598402)

    xtrabackup: Stopping log copying thread.

    xtrabackup: Transaction log of lsn (1598402) to (1598402) was copied.

 

posted by admin in 数据库 and have No Comments

Nginx 构建一个“高”可用的 PHP 集群

使用 Nginx 构建一个“高”可用的 PHP 集群

跳过没必要的介绍,直接进入主题。目前建立一个高可用集群的方案不少,可以使用硬件或软件 LVS 类构建,现在我说的方案是只用 Nginx 来进行构建。

这个集群的架构如下图:

上面我们共部署了5个节点,每个节点上配有 Nginx + PHP。这个架构的重点就在于,Nginx 不只是与本机的 PHP 通信,整个集群应该把 Nginx 部分抽象到面向业务的第一层,而 PHP 则在第二层。每层都为多节点均衡架构。

其中 Nginx 层面使用 DNS 均衡实现,DNS 负载均衡是一个很传统的方案,在单个域名下绑定多个 IP 进行轮循,可有效的把业务请求分发到多个节点上,但某节点故障时则需要有相应的解析处理,把故障的节点从 DNS 记录中删除。目前推荐使用 DNSPOD 的解析服务,可支持 API 操作。这样我们就可以自己建立一个服务器状态管理的程序,自动切换 DNS 解析。(注意:域名解析的切换需要 5~10 分钟,当然这是由域名解析记录的 TTL 值决定,为避免大量的 DNS 解析影响请求打开速度,建议 10 分钟或以上为佳)

第二层 PHP 则由 Nginx 使用 upstream 实现均衡,Nginx 本身的 upstream 就已支持节点健康维护的功能,可以放心的交给 Nginx 来做。而如果 PHP 业务层带缓存功能,则要考虑使用一致性哈希模块来实现 upstream 的均衡策略,否则节点故障对整个 PHP 集群的缓存造成大幅度的震荡。根据我们测试的数据,在普通哈希策略下,一个节点故障会导致 90% 的缓存失效,而使用一致性哈希则可降低到 50% 。并且我们的 Nginx 一致性哈希模块,还可以把故障节点的请求分发到邻近的节点,可以再提高部分缓存命中率,使得整体提升到 70% 的样子。

这样一个架构方案给我们实现了一个“高”可用的 PHP 集群,并且没有单点故障的隐患存在。DNS 解析服务是多节点,Nginx 层是多节点,PHP 层更是多节点的模式。如使用 LVS 方案,LVS 服务本身也要做一套热备,才能避免单点问题,且增加了架构复杂性。

应该选择那套架构方案还由业务决定,这里我只是提供一个新思路罢了 ;)

Nginx 一致性哈希模块:ngx_consistent_hash-1.0.tar

ngx_consistent_hash-1.1.tar.gz (Fix nginx reload bug)

使用方法:

upstream backend {
server 192.168.1.101 weight=1;
server 192.168.1.102 weight=2;
server 192.168.1.103 weight=3;
server 192.168.1.104 weight=4;
server 192.168.1.105 weight=5;
consistent_hash $host$request_uri 2;
}

consistent_hash 支持2个参数,第一个参数为哈希字符串,第二个参数为备份节点数量。当某节点故障时,将把该节点的请求分发到2个备份节点上。当然你可以设置1或更高,建议2为佳 :)

模块对 nginx 原 upstream 模块的 weight 节点权重功能进行了替换,weight 的功能是配置节点在集群中的位置顺序。(做一致性哈希,这是必须的)

 

posted by admin in 服务器,未分类 and have No Comments
Tags: , ,

页面输出缓存

随着网站规模的变大,访问量提升,网站服务器越来越不堪重负,浏览者也会对页面打开的速度怨声载道。这时候最简单的解决方案就是增加缓存。网站服务器的缓存有很多中,可以放在数据库和Web应用程序之间,也可以放在Web应用程序和Web服务器之间,还可以放在Web服务器和用户浏览器之间,甚至可以直接放在浏览器端。

其中最简单,需要配置最少的莫过于数据库和Web应用程序之间了,并且见效也最快,因为对于现代计算机系统来说IO是最大的瓶颈。常见的方法就是使用MemCache或者K-V型NoSQL数据库做缓存。

这么安逸了一段时间之后,网站的响应速度还是会降下来,如果你不想增加服务器的话,这时需要做的就是页面输出缓存了。

因为数据库和Web应用程序端的缓存只是将数据库中的键和值缓存下来,访问量大的话有一个命中率的问题,并且一个页面往往包含有大量的需要从数据库查询的值,就算数据库缓存全部命中,这其中也需要一个查询的过程,即时它很快。还有一个问题,就是对于Web应用程序来说,从获取数据到输出页面,中间还需要一些逻辑性运算和模板的渲染过程,这个过程也会消耗一段时间。

如果将一个页面响应的结果,也就是HTML页面,整体缓存下来,Web服务器直接输出缓存结果,这样的速度基本上相当于直接输出静态页面,对于服务器端的负载将会大大减轻。
对于页面输出缓存,或者有人称之为页面静态化,主要有以下几个问题:

页面个性化部分的处理。现在绝大部分网站都有登录给功能,对于同一个页面来说登录前后、不同用户登录后都会有不同的显示,比如说未登录时显示“登录或注册”,登录之后显示“欢迎用户XXX”,这样就会造成网站大部分页面都不能直接缓存。

其实这个问题是在页面个性化部分与非个性化部分合成的时间问题上。传统网站这个个性化部分也非个性化部分是直接放在Web应用程序上的,这样就导致不同用户输出页面的不同,缓存不能进行。如果把这个过程放在页面缓存程序之后,使缓存的结果相同就没有问题了。

常见的方式就是使用SSI、ESI和CSI。

SSI(Server Side Include)这个现在大部分的Web服务器都支持,可以在页面中使用<!–#include file=”/user_info.shtml”–>来替代原来个性化的部分,然后在Web服务器上就会去寻找这个.shtml文件,将它与页面合成。不过这有一个问题,ssi只能将静态文件与页面合成,这样对于做页面输出缓存意义并不大。

ESI(Edge Side Include)正是为了应付这种场合而出现的,它可以使用类似<esi:include src=”http://example.com/1.html” alt=”http://bak.example.com/2.html” onerror=”continue”/>的XML语法,在页面合成过程中调用一个动态页面,将动态页面的内容与现有网页合成。这样一来就可以将某个用户的个性化信息与缓存的页面文件合成了。ESI最大的问题就是现有Web服务器对此支持度不高。Nginx需要将第三方模块编译进来来支持ESI,代理缓存服务器中Varnish原生支持ESI。

CSI(Client Side Include)或者叫做Browser Side Include,就是在用户浏览器端将个性化信息与非个性化信息合成。说白了就是用ajax异步获取个性化信息,或者直接使用iframe显示个性化信息。实际上这个合成的过程越靠近用户浏览器端越好,这样就可以一直从Web服务器到代理服务器的缓存到CDN都可以用到这些完全相同的页面做缓存。但是使用ajax等方式有一些问题,就是对于不支持或者不开启的JavaScript的浏览器来说就不能正常访问页面了,现在很多网站都要考虑到手机客户端,其中不支持JavaScript的占大多数。并且大量使用ajax的话对用户浏览器来说也是一种负担,并且会造成页面加载很“卡顿”的感觉。

具体的做法还是依赖实际环境来决定。

剩下需要解决的方式是如何来缓存页面。

使用代理缓存服务器是一个比较不错的主意,比如Squid还有比较新的Varnish,它们都可以架设在Web服务器前端作为代理缓存服务器,将页面缓存下来。当页面需要更新的时候可以给它发送一个Purge请求加具体页面URL,就可以使代理缓存服务器去访问Web服务器,重新生成一个新的页面,然后将现有的页面缓存失效。这个过程中当新的用户访问请求达到时,代理缓存服务器还是使用之前的缓存,新的缓存页面生成结束后才使过期的页面失效。这样就不用担心更新缓存过程中所有用户请求都去直接访问Web服务器造成大量的压力了。这其中有一个问题,就是触发这个更新动作的用户,比如说他发布了一条回复造成页面更新,如果页面更新请求与页面缓存更新两个动作是异步的话,假如他的网速足够快就会看到自己刚才发布的帖子没有显示出来,造成重复发帖等动作。这个问题接下来再来想办法处理。

如果不想另外搞一个代理服务器的话,Nginx的fastcgi cache是一个好东西,可以直接将fastcgi的页面缓存下来。配合一个第三方的模块cache purge,可以通过访问/purge/url的方式来时缓存过期。另外Nginx+proxy cache+cache purge也可以达到上面Squid和Varnish的作用。

剩下还有一种方式,使用Nginx的rewrite,将缓存保存为一个静态文件,先检查静态页面是否存在,存在的话rewrite到此,不存在则访问Web应用程序。这样还需要另外配合一个独立的进程,来生成缓存页面。当Web应用程序触发更新时给此进程发送一个信号,缓存进程收到此信号后去Web服务器端或者Web应用程序端请求页面(为了做到松耦合和以后的服务器分离最好直接从Web服务器端),将请求生成的页面文件直接覆盖远缓存的静态文件,这样就可以更新缓存,并且在缓存更新过程中访问者依然可以使用之前的缓存文件。

还有一个问题,当很多用户在同一个时间点内同时触发一个页面的更新动作,这样就会导致此页面频繁更新,并且这些更新是不必要的,这就是所谓的惊群问题。
防止此事件发生,一个解决方案是使用队列。

一般页面发生内容变化是在提交POST请求之后,在此时给缓存更新系统发送一条消息,记录发生更新动作的类型、ID(比如说帖子更新,更新的ID)。缓存更新系统在接受到此消息时将消息进行预处理,根据配置文件计算出影响更新的页面(此帖子的页面,帖子列表的页面,等等)。

将此页面的URL插入进队列,更新程序在队列另一端取URL,每取一次URL就过滤一遍整个队列,将相同的URL队列消息删除出队列。这样就可以保证更新依次页面,就可以相应所有更新事件。取出后依据使用的缓存系统发送相应的Purge请求或者自主生成新的缓存页面覆盖老的野蛮来更新缓存。

这种去重复的队列实现可以用现有的模块,比如Python的一个Queue模块,继承此模块中的类并重写几个方法即可实现这种去重的队列。还可以使用现有的队列系统,甚至直接使用数据库来实现队列。使用数据库有一个好处,就是当整个系统Down掉的时候,系统重启后队列中的消息还存在,可以继续更新这些页面的缓存。如果直接使用内存中的队列的话系统Down掉重启就会导致一些未处理的队列消息丢失,导致这些页面的缓存都没有更新。这种情况出现的几率还有出现后对系统的影响需要根据实际情况斟酌,论坛系统如果发帖不是十分频繁,偶尔某个帖子或者回复没有出现并不是非常严重的问题。

一个好的系统应该是针对发生故障的情况而设计的。假如缓存系统出现问题,导致没有向缓存服务器发送更新请求,这时所有更新动作都不会得到相应,导致用户重复提交数据,可能会发生一些问题。这时如果能停掉缓存服务器,让用户直接访问Web应用程序或许是一个好主意(或者如果没有缓存的话服务器能被直接大量直接访问干掉),如果去做是一个问题。

Some Tips:

上面说的如果异步处理更新动作与缓存更新的话,可能会使更新触发者看不到自己更新的数据。这时可以使用一些小花招,比如现在大部分的论坛系统在发帖后跳转到一个“3秒后跳转到帖子页面”,就可以给缓存系统提供充分的更新缓存时间,对于用户体验来说也不会大打折扣。

有些页面不能使用缓存,比如说帖子列表页面。因为帖子列表页面是会随着最后回复时间来动态更新排列顺序的,一个新帖或者回复可能会导致所有帖子列表分页内容发生变化,而帖子列表分页可能有几千甚至几万页,全部都进行更新的话显然是不可能也没有必要的。因此这些页面不适用页面输出缓存,但我们可以只缓存帖子列表的第一页或者前几页,因为绝大部分的访问请求都是来自与这几个页面,每次更新动作都触发这几个页面进行缓存更新也是没有问题的。

假如网站每日发新帖的数量非常高,导致帖子列表更新十分频繁,这时可以使用另外一种更新触发机制,就是按时间来触发更新。这样定时更新的频率比之前按动作进行更新会少一些,并且也不会过分加重队列的负担。

网站首页的信息可能会比较复杂,触发其更新的来源可能会很多,更新一次的成本也较高,而首页对于事实性的要求也没有那么高(比如说在某个板块发布新贴,这时在首页的最新帖子列表中没有看到此贴,对于绝大部分用户来说并不是什么问题),因此也试用于按时间进行更新的机制,并且这个更新时间的间隔可以适当的拉长一些。

类似的还有帖子回复页,此页面也是一个列表排序页面,但是是顺序时间排列的(帖子列表为倒序时间排列的),因此也十分适用与使用缓存。如果网站当初设计的功能为显示所有楼层,删除某一楼层的话此位置消失,这样的话如果删除一个楼层将会导致此页面和接下来所有页面的内容发生变化。因此在网站设计时最好设计成这样:删除一条回复,此回复还在,只不过内容改为了“评论已删除”,这样就不会触发所有后来页面进行缓存更新了

 

posted by admin in 未分类 and have No Comments
Tags: ,

设计实例对比:MySQL vs MongoDB

MySQL是关系型数据库中的明星,MongoDB是文档型数据库中的翘楚。下面通过一个设计实例对比一下二者:假设我们正在维护一个手机产品库,里面除了包含手机的名称,品牌等基本信息,还包含了待机时间,外观设计等参数信息,应该如何存取数据呢?

如果使用MySQL的话,应该如何存取数据呢?

如果使用MySQL话,手机的基本信息单独是一个表,另外由于不同手机的参数信息差异很大,所以还需要一个参数表来单独保存。

CREATE TABLE IF NOT EXISTS `mobiles` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(100) NOT NULL,
    `brand` VARCHAR(100) NOT NULL,
    PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `mobile_params` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `mobile_id` int(10) unsigned NOT NULL,
    `name` varchar(100) NOT NULL,
    `value` varchar(100) NOT NULL,
    PRIMARY KEY (`id`)
);
INSERT INTO `mobiles` (`id`, `name`, `brand`) VALUES
(1, 'ME525', '摩托罗拉'),
(2, 'E7'   , '诺基亚');
INSERT INTO `mobile_params` (`id`, `mobile_id`, `name`, `value`) VALUES
(1, 1, '待机时间', '200'),
(2, 1, '外观设计', '直板'),
(3, 2, '待机时间', '500'),
(4, 2, '外观设计', '滑盖');

注:为了演示方便,没有严格遵守关系型数据库的范式设计。

如果想查询待机时间大于100小时,并且外观设计是直板的手机,需要按照如下方式查询:

 

注:为了演示方便,没有严格遵守关系型数据库的范式设计。

如果想查询待机时间大于100小时,并且外观设计是直板的手机,需要按照如下方式查询:

SELECT * FROM `mobile_params` WHERE name = '待机时间' AND value > 100;
SELECT * FROM `mobile_params` WHERE name = '外观设计' AND value = '直板';

注:参数表为了方便,把数值和字符串统一保存成字符串,实际使用时,MySQL允许在字符串类型的字段上进行数值类型的查询,只是需要进行类型转换,多少会影响一点性能。 www.yzyedu.com

两条SQL的结果取交集得到想要的MOBILE_ID,再到mobiles表查询即可:

 

SELECT * FROM `mobiles` WHERE mobile_id IN (MOBILE_ID)

如果使用MongoDB的话,应该如何存取数据呢?

如果使用MongoDB的话,虽然理论上可以采用和MySQL一样的设计方案,但那样的话就显得无趣了,没有发挥出MongoDB作为文档型数据库的优点,实际上使用MongoDB的话,和MySQL相比,形象一点来说,可以合二为一:

 

db.getCollection("mobiles").ensureIndex({
    "params.name": 1,
    "params.value": 1
});
db.getCollection("mobiles").insert({
    "_id": 1,
    "name": "ME525",
    "brand": "摩托罗拉",
    "params": [
        {"name": "待机时间", "value": 200},
        {"name": "外观设计", "value": "直板"}
    ]
});
db.getCollection("mobiles").insert({
    "_id": 2,
    "name": "E7",
    "brand": "诺基亚",
    "params": [ www.yzjxsp.com
        {"name": "待机时间", "value": 500},
        {"name": "外观设计", "value": "滑盖"}
    ]
});

如果想查询待机时间大于100小时,并且外观设计是直板的手机,需要按照如下方式查询:

 

db.getCollection("mobiles").find({
    "params": {
        $all: [
            {$elemMatch: {"name": "待机时间", "value": {$gt: 100}}},
            {$elemMatch: {"name": "外观设计", "value": "直板"}}
        ]
    }
});

注:查询中用到的$all,$elemMatch等高级用法的详细介绍请参考官方文档中相关说明。

MySQL需要多个表,多次查询才能搞定的问题,MongoDB只需要一个表,一次查询就能搞定,对比完成,相对MySQL而言,MongoDB显得更胜一筹。

【编辑推荐】

 

 

 

posted by admin in 未分类 and have No Comments