四、数据结构和算法
1、求一串数字序列中的连续子串最大和,比如arr=1 -2 3 -1 2
,连续子串最大和就是3 -1 2
组成的max_sum=4。
- 分析:这是一道动态规划的题目,可以设子问题dp[i]为以第i个数字结尾的连续子串的最大和,所以我们能得到dp[1]=1,dp[2]=-1,dp[3]=3,dp[4]=2,dp[5]=4,这5个数中最大的数
max{dp[i]}
就是我们要找的。 - 如果dp[i-1]<=0,那么dp[i]=arr[i];如果dp[i-1]>0,则有必要把前面的数加入求和dp[i]=arr[i]+dp[i-1]。
int MaxSubSum(int *arr, int n)
{
int sum=0, b=0; //只用一个b记录dp[i],更节省内存
for (int i=1;i<=n; i++)
{
if (b>0) b+=a[i];
else b=a[i];
if (b>sum) sum=b;
}
return sum;
}
2、寻找100范围内的素数的算法,对于找到的前面的每个素数的n倍都必然不是素数,都可以剔除检查
五、网络
1、TCP三次握手,四次挥手状态改变过程?
- 所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手。
第一次握手(SYN=1, seq=x):
客户端发送一个 TCP 的控制位
的SYN 标志位置1的包,指明客户端打算连接的服务器的端口,以及初始序号 X,保存在包头的序列号(Sequence Number)字段里。
发送完毕后,客户端进入 SYN_SEND 状态。
第二次握手(SYN=1, ACK=1, seq=y, ACKnum=x+1):
服务器发回确认包(ACK)应答。即 SYN 标志位和 ACK 标志位均为1。服务器端选择自己 ISN 序列号,放到 Seq 域里,同时将确认序号(Acknowledgement Number)设置为客户的 ISN 加1,即X+1。 发送完毕后,服务器端进入 SYN_RCVD 状态。
第三次握手(ACK=1,ACKnum=y+1)
客户端再次发送确认包(ACK),SYN 标志位为0,ACK 标志位为1,并且把服务器发来 ACK 的序号字段+1,放在确定字段中发送给对方,并且在数据段放写ISN的+1
发送完毕后,客户端进入 ESTABLISHED 状态,当服务器端接收到这个包时,也进入 ESTABLISHED 状态,TCP 握手结束。
为什么就需要3次握手,不是2次或者4次?
三次握手的目的:是为了确认双方都有收发数据的能力或者说想确定双通道通畅
。
Client->Server:表明C有发数据的能力,发了seq序列号x。
S->C:回应x+1表明S有收数据的能力收到过x,也有发数据的能力并且发了序列号y。
C->S:回应y+1表明C也有收数据的能力。
至此C S都互相确认了对方有收发数据的能力,然后就可以放心的向对方数据了。若是只有两次,那么Server是不能确认Client能够收数据的。两次达不到目的,3次能搞定的事情,4次就显得多余了。
》从另一方面来讲,若是默认双方都能收发数据,两次握手时,如果因为网络拥塞先前的client某个连接请求被延迟,而超时重发连接请求后连接成功然后收发数据结束后断开连接了。但是之前延迟的连接请求又最终发到了server端,server以为是个新连接然后就准备给client发送数据,但是client此时并没有连接,因此收不到server的数据,导致server不停的重发数据直至认为应该断开连接,但是也会造成资源浪费。
》假设不采用“三次握手”而是两次,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。
》这个问题的本质是, 信道不可靠, 但是通信双方需要就某个问题达成一致.
而要解决这个问题, 无论你在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足"在不可靠信道上可靠地传输信息"这一需求所导致的. 请注意这里的本质需求,信道不可靠, 数据传输要可靠. 三次达到了, 那后面你想接着握手也好, 发数据也好, 跟进行可靠信息传输的需求就没关系了. 因此,如果信道是可靠的, 即无论什么时候发出消息, 对方一定能收到, 或者你不关心是否要保证对方收到你的消息, 那就能像UDP那样直接发送消息就可以了.”。这可视为对“三次握手”目的的另一种解答思路。后面一段话意思就是如果想确定双通道通畅
,必须使用三个包的发送接收,也就是三次握手。
- TCP 的连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),也叫做改进的三次握手。客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close() 操作即可产生挥手操作。
第一次挥手(FIN=1,seq=x)
假设客户端想要关闭连接,客户端发送一个 FIN 标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
发送完毕后,客户端进入 FIN_WAIT_1 状态。
第二次挥手(ACK=1,ACKnum=x+1)
服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
发送完毕后,服务器端进入 CLOSE_WAIT 状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。
第三次挥手(FIN=1,seq=y)
服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
发送完毕后,服务器端进入 LAST_ACK 状态,等待来自客户端的最后一个ACK。
第四次挥手(ACK=1,ACKnum=y+1)
客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。
服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 - 客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端重发的FIN 报文,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入 CLOSED 状态。若是收到了重复的FIN报文,则要再次回应ACK。
为什么需要4次挥手?
那可能有人会有疑问,在tcp连接握手时为何ACK是和SYN一起发送,这里ACK却没有和FIN一起发送呢。原因是因为tcp是全双工模式,接收到FIN时意味着对方将没有数据再发来,但是本方还是可以继续发送数据到对方。因为每两次握手确认一边不再发数据,两边都不发数据就需要4次握手了。
2、TIME_WAIT状态存在的理由和作用?
- 虽然双方都同意关闭连接了,而且握手的4个报文也都协调和发送完毕,按理可以直接回到CLOSED状态(就好比从SYN_SEND状态到ESTABLISH状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的ACK报文会一定被对方收到,因此对方处于
LAST_ACK状态下的SOCKET可能会因为超时未收到ACK报文,而重发FIN报文
,所以这个TIME_WAIT状态的作用就是用来重发可能丢失的ACK报文
。 - TIME_WAIT状态所带来的影响
1、当某个连接的一端处于TIME_WAIT状态时,该连接将不能再被使用。事实上,对于我们比较有现实意义的是,这个端口将不能再被使用。
2、某个端口处于TIME_WAIT状态(其实应该是这个连接)时,这意味着这个 TCP 连接并没有断开(完全断开),那么,如果你bind这个端口,就会失败。对于服务器而言,如果服务器突然坏掉了,那么它将无法再2MSL内重新启动,因为bind会失败。
3、解决这个问题的一个方法就是设置 socket (setsockopt()函数)的SO_REUSEADDR选项的值设为1。这个选项意味着你可以重用一个端口地址。
3、ping网络主机之间通不通用到什么协议?
- ICMP(因特网控制报文协议)
- ICMP协议是IP层的附属协议,是介于IP层和TCP层之间的协议,一般认为属于IP层协议。IP协议用它来 与其他主机或路由器交换错误报文和其他的一些网络情况。在ICMP包重携带了控制信息和故障恢复信 息。主要用于路由器主机向其他路由器或者主机发送出错报文的控制信息
- 简单地说,ping就是给目标IP地址发送一个 ICMP 回显请求,并要求对方返回一个 ICMP 回显应答来确定两台网络机器是否连通,时延是多少。
4、什么时候使用TCP,什么时候使用UDP?
- TCP是稳定、可靠、面向连接的传输层协议,它在传递数据前要三次握手建立连接,在数据传递时,有ACK确认机制、重传机制、流量控制、拥塞控制等,可以保证数据的正确性和有序性。
- TCP 提供一种面向连接的、可靠的字节流服务。
在一个 TCP 连接中,仅有两方进行彼此通信。广播和多播不能用于 TCP。
TCP 使用校验和,序列号seq-ack确认和重传机制来保证可靠传输
。
TCP 给数据分节进行排序,并使用累积确认保证数据的顺序不变和非重复。
TCP 使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制。 - UDP是无连接的数据传输协议,端与端之间不需要建立连接,且没有类似TCP的那些机制,会发生丢包、乱序等情况。因此有低时延优点。
- TCP是数据流模式,而UDP是数据报模式。
- 需要可靠传输对时延要求不高时用TCP,对时延要求高并且允许一定的丢包发生时用UDP。比如游戏中,对于那些打斗视频画面要求低时延而且允许一定的丢包发生那就用UDP传输,而如果用TCP会因为一些丢包引发重传而使得时延很高;而对于游戏中的信息管理操作交易操作等要求可靠的就要TCP,还有棋牌类游戏也是可靠性高于时延要求使用TCP。
5、为什么 TCP 叫数据流模式? UDP 叫数据报模式?
- 所谓的“流模式”,是指TCP发送端发送几次数据和接收端接收几次数据是没有必然联系的,比如你通过 TCP 连接给另一端发送数据,你只调用了一次 write,发送了100个字节,但是对方可以分10次收完,每次10个字节;你也可以调用10次 write,每次10个字节,但是对方可以一次就收完。
原因:
这是因为TCP是面向连接的,一个 socket 中收到的数据都是由同一台主机发出,且有序地到达,所以每次读取多少数据都可以。 - 所谓的“数据报模式”,是指UDP发送端调用了几次 write,接收端必须用相同次数的 read 读完。UDP 是基于报文的,在接收的时候,每次最多只能读取一个报文,报文和报文是不会合并的,如果缓冲区小于报文长度,则多出的部分会被丢弃。
原因:
这是因为UDP是无连接的,只要知道接收端的 IP 和端口,任何主机都可以向接收端发送数据。 这时候, 如果一次能读取超过一个报文的数据, 则会乱套。
6、IP地址的分类?私有IP(局域网IP)是哪些——相对于公网IP来说?
- IPv4是4字节32位地址,被分为A\B\C三类。
- A类第一个bit位固定为0,1字节的网络号和3字节的主机号;A类的私有地址在10.0.0.0到10.255.255.255,共有2^24个可用的私有IP地址。
- B类前两个bit位固定10,2字节的网络号和2字节的主机号;B类的私有地址是在172.16.0.0到172.31.255.255范围,共有16x2^16个可用的私有IP地址。
- C类前3个bit位固定110,前3字节的网络号和1字节的主机号;C类私有地址为192.168.0.0到192.168.255.255,共有2^16次方个可用的私有IP地址。
- 由于IPv4最大的问题在于网络地址资源有限,严重制约了互联网的应用和发展。IPv6地址是128位16字节的。格式为X:X:X:X:X:X:X:X,每个X是16进制的4个数字表示16位,故8x16=128位。
7、http协议和各个状态码表示什么意思?
- http协议底层是应用tcp协议,分为每次用完就断开的短连接和用完保持的长连接。
- http是无状态的协议是指,服务器不会对浏览器客户端的行为进行记录,每次请求服务器都当做是一次新的行为。但是像缓存行为那是客户端自己记录的,与服务器无关。客户端想要再次获取某个资源时,向服务器发送一个包询问在上一次访问网站的时间后是否更改了页面,如果服务器没有更新,显然不需要把整个网页传给客户端,客户端只要使用本地缓存即可,如果服务器对照客户端给出的时间已经更新了客户端请求的网页,则发送这个更新了的网页给用户。
- HTTP 请求分为三个部分:状态行、请求头、消息主体。类似于下面这样:
<method> <request-URL> <version>
<headers>
<entity-body>
- HTTP定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。URL全称是资源描述符,我们可以这样认为:一个URL地址,它用于描述一个网络上的资源,而 HTTP 中的GET获取,POST修改,PUT增加,DELETE删除资源。
- HTTP响应也是三部分:状态行、响应头、响应正文。状态行由协议版本、数字形式的状态代码、及相应的状态描述,各元素之间以空格分隔。
200 OK 客户端请求成功
301 Moved Permanently 请求的资源永久移动
302 Moved Temporarily 请求的资源临时移动
304 Not Modified 文件未修改,可以直接使用浏览器缓存的文件,无需再从服务器下载。
400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized 请求未经授权,则要求客户端再次发送用户名密码等认证信息。这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因
404 Not Found 请求的资源不存在,例如,输入了错误的URL
500 Internal Server Error 服务器内部发生不可预期的错误,导致无法完成客户端的请求。
503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。
8、 sip协议和上面的http非常像,包含了并且扩展了HTTP/1.1的一些状态码:
临时应答(1XX)
100 Trying 正在处理中
180 Ringing 振铃
181 call being forwarder 呼叫正在前向
182 queue 排队
181* session progress 会话进行
305 use proxy 用户代理
380 alternative service 替代服务
请求失败(4XX)
405 method no allowed 方法不允许
406 not acceptable 不可接受
407 proxy authentication required 代理需要认证
408 request timeout 请求超时
服务器失败(5XX)
501 not implemented 不可执行
502 bad gateway 坏网关
503 service unavailable 服务无效
504 server time-out 服务器超时
505 version not supported 版本不支持
全局性错误(6XX)
600 busy everywhere 全忙
603 decline 丢弃
604 does not exist anywhere 不存在
606 not acceptable 不可接受
9、访问一个网站失败,如何定位故障?
- 首先访问一个其他知名网站,查看是否是自身网络断开问题,比如
www.baidu,com
,若是能访问,则说明自身电脑可以访问外网。 - 可以询问其他地方的朋友是否能访问该网站。看看是不是该网站自己出了问题,还可以观察浏览器的返回http的状态码查看对应的问题。
- 使用win+R进入控制台输入ping命令,可验证是否输入的网址未被DNS服务器记录对应的ip,导致无法访问,此时返回
ping请求找不到主机
。若是返回丢包超时,则有可能是禁止了ping命令,防火墙拦截或者是某个网络节点出了故障。 - 然后可以用trace router命令
tracert
追踪30个节点内的路由连通情况,若是从某个ip节点之后到第30个地址都是请求超时,说明就是从这个节点之后网络断开的。
六、linux操作系统
1、举几个常用的linux命令?
- cd,ls,cp,mv,rm,pwd,mkdir,rmdir,touch,cat,find -name,locate,vim,service iptables stop,ifconfig,ip addr show,
- ps -ef|grep freeswitch,kill -9 pid,service netstat restart,netstat -an | grep ESTABLISHED
- tar -cvf,tar -xvf,zip,unzip,gzip,gunzip,df,du,top
- yum -y install,apt-get -y install
- link,link -s,ls -i
https://www.jianshu.com/p/a0e799ffb876
2、linux中想要将一个文件中的字符串A全部用字符串B替换,命令怎么写?
-
#sed -i "s/A/B/g" file.txt
-i表示直接操作文件内容insert,而不用打印到屏幕(如果不用-i那么只会输出临时文本到屏幕,而不会写入到原文件,当然也可以用>file1.txt重定向输出到另一个文件)。s是开始g是到末尾。sed全名叫stream editor,流编辑器,用程序的方式来编辑文本。 - 使用
#vim file
先打开文件,然后再在normal模式下(相对于插入模式编辑):%s/A/B/g
回车执行。 -
#sed 's/^/#/g' file.txt
对文件中每一行行首(通过正则符号^匹配到行首)添加#符号,对于一些脚本文件的注释很有用。 -
#sed 's/$/---/g' file.txt
对每一行的行尾($匹配到)添加---字符串。
3、正则表达式的匹配规则?
^ 表示一行的开头。如:/^#/ 以#开头的匹配。
$表示一行的结尾。如:/}$/ 以}结尾的匹配。
< 表示词首。 如:<abc 表示以 abc 为首的詞。
> 表示词尾。 如:abc> 表示以 abc 結尾的詞。
. 表示任何单个字符。
* 表示任何0或多个字符。
[ ] 字符集合。 如:[abc] 表示匹配a或b或c,还有 [a-zA-Z] 表示匹配所有的26个字符中的一个。如果其中有^表示反,如 [^a] 表示非a的一个字符。[0-9]表示匹配0到9的一个数字。
4、awk命令选定分隔符?
- 默认用空格作为各列的分隔符,想用其他字符需要用
-F
参数
5、Linux命令去重统计排序(awk命令去重保留原顺序,sort, uniq命令排序去重统计)?
-
awk '!a[$0]++' file.txt > file1.txt
对文件各行去重后重新输出到另一个文件,并且各行保留原顺序,其实主要思想是前面输出过的一行字符串,后面再遇到相同的将不会输出。 -
sort file.txt | uniq > file1.tet
对文件先排序,然后再用uniq命令去重(只能是相邻行,所以要先排序将重复行放到相邻的位置),最后再输出到另一个文件保存而不是只打印出来。 - https://blog.csdn.net/feng973/article/details/73849586
6、Nginx服务器架构?
- worker 进程又是如何处理请求的呢?我们前面有提到,worker 进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供 80 端口的 http 服务时,一个连接请求过来,每个进程都有可能处理这个连接,怎么做到的呢?首先,每个 worker 进程都是从 master 进程 fork 过来,在 master 进程里面,先建立好需要 listen 的 socket(listenfd)之后,然后再 fork 出多个 worker 进程。所有 worker 进程的 listenfd 会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有 worker 进程在注册 listenfd 读事件前抢 accept_mutex,抢到互斥锁的那个进程注册 listenfd 读事件,在读事件里调用 accept 接受该连接。当一个 worker 进程在 accept 这个连接之后,就开始读取请求,解析请求,处理请求,产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到,一个请求,完全由 worker 进程来处理,而且只在一个 worker 进程中处理。
- 那么,Nginx 采用这种进程模型有什么好处呢?当然,好处肯定会很多了。首先,对于每个 worker 进程来说,独立的进程,不需要加锁,所以省掉了锁带来的开销,同时在编程以及问题查找时,也会方便很多。其次,采用独立的进程,可以让互相之间不会影响,一个进程退出后,其它进程还在工作,服务不会中断,master 进程则很快启动新的 worker 进程。当然,worker 进程的异常退出,肯定是程序有 bug 了,异常退出,会导致当前 worker 上的所有请求失败,不过不会影响到所有请求,所以降低了风险。当然,好处还有很多,大家可以慢慢体会。
http://wiki.jikexueyuan.com/project/nginx/nginx-framework.html
7、C/S架构和B/S结构?
- C/S是Client/Server,即tcp/udp中的客户端和服务器架。
- B/S是Browser/Server,即浏览器和服务器,是web的架构。
8、gdb调试常用命令?
- 先编译生成带调试信息的可执行文件:
#gcc -g test.c -o test
- 然后使用gdb命令运行可执行文件:
#gdb test
然后进入gdb调试命令行环境。 - (gdb) l <-------------------- l命令相当于list,从第一行开始列出源码。
- (gdb) <-------------------- 直接回车表示,重复上一次命令
- (gdb) start <-------------------- //开始调试,运行到第一个断点处停止。
- (gdb) break 16 <-------------------- 设置断点,在源程序第16行处。break命令也可简写成b。+16表示在16行后停止,-16表示在16行前停止。
- (gdb) break func <-------------------- 设置断点,在函数func()入口处。
- (gdb) info break <-------------------- 查看断点信息。
- (gdb) delete breakpoints 2 <-------------------- //删除某个断点
- (gdb) bt <--------------------- backtrace命令,查看当前运行的函数的堆栈(函数参数、局部变量、该函数的函数调用栈等)。
- (gdb) finish <--------------------- 执行完并退出当前函数。
- (gdb) r <--------------------- 重新开始运行程序,run命令简写,运行到第一个断点处停止。
- (gdb) n <--------------------- 单条语句执行,next命令简写。
- (gdb) set var sum=0 <--------------------- //修改变量值
- (gdb) c <--------------------- 继续运行程序,continue命令简写,运行到下一个断点处停止。
- (gdb) p i <--------------------- 打印变量i的值,print命令简写。
- (gdb) q <--------------------- quit,退出gdb,回到linux命令行。
- 程序发生段错误或总线错误等会产生core dump ,然后留下一个core文件,可用
#gdb core
运行此文件,查看出错的信息。 - 调试已运行的程序
————————
两种方法:
1、在UNIX下用ps查看正在运行的程序的PID(进程ID),然后用gdb PID格式挂接正在
运行的程序。
2、先用gdb 关联上源代码,并进行gdb,在gdb中用attach命令来挂接进程的PID。并用
detach来取消挂接的进程。 - Core dump叫做核心转储,它是进程运行时在突然崩溃的那一刻的一个内存快照。操作系统在程序发生异常而异常在进程内部又没有被捕获的情况下,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在一个文件里。(linux中如果内存越界会收到SIGSEGV信号,然后就会core dump)产生段错误或者总线错误。
- 产生core dump后会在可执行文件的目录下产生一个core文件(若没有设置则可能不产生)。
- 使用ulimit -c unlimited来设置无限大,则任意情况下都会产生core文件。
- 使用命令#gdb 可执行程序 core.xxx,然后再在gdb环境中输入where或者bt(backtrace)就可以看到产生段错误的地方。注意使用where的前提是该可执行文件是gcc -g 即加了gdb调试编译得到的,然后用where才可以看到错误的行号。否则看不到行号,只会和用bt命令一样,把运行经过的函数栈回溯(backtrace)显示出来。
- 显示了带编号的函数栈后,frame addr(函数帧数)或者简写f n 跳转到core堆栈的第n帧我们自己的函数。然后可以用disassemble打开该帧函数的反汇编代码,有个箭头指向最终停止程序执行的地方,上一行就是出错的行。
https://blog.csdn.net/sunxiaopengsun/article/details/72974548
》》》造成segment fault,产生core dump的可能原因
1.内存访问越界
a) 由于使用错误的下标,导致数组访问越界
b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符
c) 使用strcpy, strcat, sprintf, strcmp, strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy, strlcpy, strncat, strlcat, snprintf, strncmp, strncasecmp等函数防止读写越界。
2 多线程程序使用了线程不安全的函数。
3 多线程读写的数据未加锁保护。对于会被多个线程同时访问的全局数据,应该注意加锁保护,否则很容易造成core dump
4 非法指针
a) 使用空指针
b) 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,或者这种结构或类型的数组,否则不要将它转换为这种结构或类型的指针,而应该将这段内存拷贝到一个这种结构或类型中,再访问这个结构或类型。这是因为如果这段内存的开始地址不是按照这种结构或类型对齐的,那么访问它时就很容易因为bus error而core dump.
5 堆栈溢出.不要使用大的局部变量(因为局部变量都分配在栈上),这样容易造成堆栈溢出,破坏系统的栈和堆结构,导致出现莫名其妙的错误。
9、从C源代码到可执行文件的编译链接过程?
gcc test.c -o test ,这一行命令就可以将test.c源代码生成可执行文件test,下面是拆解这个过程。
预处理》编译》汇编》链接》可执行文件
总结这个变化过程为test.c 》 test.i 》 test.s 》 test.o 》 test
-
#gcc test.c -E -o test.i
预处理过程,将c文件去注释、宏替换、展开头文件、条件编译。得到的还是ASCII码形式的文本C语言源码。 -
#gcc test.i -S -o test.s
编译过程,将预处理后的C语言源码编译成ASCII码文本形式的汇编代码,期间会进行代码优化,汇总函数变量等符号。 -
#gcc test.s -c -o test.o
汇编过程,将ASCII码文本形式的内容汇编成二进制目标文件,合并各个section,合并符号表。 -
#gcc test1.o test2.o -o test
链接过程,将多个.o目标文件链接成一个可执行文件,合并各个.obj文件的section,合并符号表,进行符号解析;符号地址重定位。
我们用gcc编译程序时,常常会用到“-I”(大写i)后接头文件地址,“-L”(大写l)后接链接库文件地址,“-l”(小写l)指定需链接的库文件等参数(当既有动态库world.so又有静态库world.a时默认使用动态库,若要首选静态库则要加上-static选项),下面做个记录:例:
gcc -o hello hello1.c hello2.c hello3.c -I/home/hello/include -L/home/hello/lib -lworld
10、静态库和动态库生成和区别?
- 静态库.a——archives,链接时拷贝需要的函数内容到可执行文件,因此可执行文件会比较大,链接完成后不再需要静态库了。
- 静态库的生成:
#ar cr libtest.a test1.o test2.o
ar——archives静态库,cr——create创建。 - 动态库.so——shared object,共享动态库,所谓共享的意思即为所有动态库共享一份源代码,而不是像每个静态库那样都拷贝一份源代码,节省空间,程序运行时再载入需要的库,linux链接时默认首选动态库。
- 动态库生成:
#gcc -shared -fPIC -o libtest.so test1.o test2.o
,PIC是指位置无关代码(Position-Independent Code)。 - 还可在程序中进行动态库的装载和卸载,而不是在编译时就链接好
头文件<dlfcn.h>
void* handle = dlopen("libtest.so", RTLD_LAZY);
//根据地址加载动态库,并选定加载模式是立即加载RTLD_NOW还是用到时再加载RTLD_LAZY。加载失败时返回空。
void (*test_func)() = dlsym(handle, "test");
根据提供的函数名test从动态库中返回该函数的调用地址并赋给一个函数指针。
(*test_func)();
执行该函数,也可以是test_func();
int flag = dlclose(handle);
动态库卸载函数,传入的参数是加载时返回的句柄,返回值为0表示成功,非0错误。
七、数据库管理系统(DBMS——MySQL是一种关系型DBMS)
- 注意数据库database和数据库管理系统的区别
0、MySQL基于tcp协议?
- 同一台服务器上的MySQL客户端和服务器可以是用Unix socket进程间通信协议。
同一台或不同的服务器都可以远程连接MySQL数据库,采用的就是TCP协议通信。 - MySQL服务器默认监听3306端口。应用程序作为客户端去TCP连接3306端口然后发送sql请求然后得到响应。
- TCP握手协议:客户端连接MySQL服务器首先也是会经过TCP的3次握手,然后连接成功。
- MYSQL握手协议:接着,进行mysql认证过程。(1)服务端首先会发一个握手包到客户端,(2)然后客户端向服务端发送认证信息(用户名,密码等),(3)服务端收到认证包后,会检查用户名与密码是否合法,并发送包告知客户端认证信息。如果合法,则登陆成功,否则,登陆失败连接报错。
问题
(1).Unix socket方式登陆与TCP方式登陆有什么区别和联系?
Unix socket是实现进程间通信
的一种方式,mysql支持利用Unix socket来实现客户端-服务端的通信,但要求客户端和服务端在同一台机器上。对于unix socket而言,同样也是一种套接字,监听线程会同时监听TCP socket和Unix socket,接受到请求然后处理,后续的处理逻辑都是一致的,只不过底层通信方式不一样罢了。
mysql -h127.0.0.1 –P3306 –uxxx –pxxx [TCP通信方式,需要指明host、Port]
mysql -uxxx –pxxx –S/usr/mysql/mysql.sock [unix socket通信方式,不需要h\P]
(2).监听socket是否与通信socket公用一个端口?
我们知道,服务端一直有一个监听socket在3306端口监听,等待新进来的客户请求,一旦一个请求过来,服务端会重新创建一个新的通信socket,这个新的socket专门用于与这个客户通信,而监听socket则继续监听。虽然是2个套接字,但监听socket和通信socket都是同一个端口,通过netstat可以确认这个问题。
(3).连接超时参数connect_timeout在何时作用?
这个参数实质就是在MYSQL认证过程起作用,如果在这个过程中,客户端超过connect_timeout时间仍然没有发送密码认证包过来,则会主动断开连接。
1、事务(transaction)是什么?
- 简单说,一个事务就是一组SQL语句。
- 在数据库系统中,一个事务是指:由一系列数据库操作组成的一个
完整的
逻辑过程。例如银行转帐,从原账户扣除金额
,以及向目标账户添加金额
,这两个数据库操作的总和,
构成一个完整的逻辑过程,不可拆分
。这个过程被称为一个事务。 - MySQL从5.5.5版本开始默认使用InnoDB作为存储引擎,这个存储引擎支持事务;然而之前的默认的MyISAM存储引擎是不支持事务性的。
- 执行BEGIN命令开启一个事务,若一系列数据库操作命令中有失败的将会执行ROLLBACK命令恢复原状,当所有命令成功执行时会执行COMMIT命令提交,确保事务结束并且这个表得到正确的更新。
2、事务有几个特性?分别是什么?
- 四个特性,ACID(英语意思:酸)
- A 原子性(atomicity,或称不可分割性)一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- C 一致性(consistency)在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
- I 隔离性(isolation,又称独立性)数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- D 持久性(durability)事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
3、MySQL数据库基本操作命令
- 注意: MySQL语句以分号(;)作为语句的结束, 若在语句结尾不添加分号时, 命令提示符会以 -> 提示你继续输入(有个别特例, 但加分号是一定不会错的);
-
show databases;
查看当前已经创建的数据库 -
create database samp_db;
创建数据库,为了便于在命令提示符下显示中文, 在创建时通过后加 character set gbk 将数据库字符编码指定为 gbk。 -
mysql -D 所选择的数据库名 -h 主机名 -u 用户名 -p
再输入密码,表示登录时指定使用的数据库;也可以不指定-D db登录后,再用命令use samp_db;
(也可不加分号)选择该数据库进行执行。选择成功后会提示: Database changed。 -
show tables;
查看当前已经存在的表 -
create table 表明(列名);
创建表命令
create table tab_new like tab_old;
(使用旧表创建新表)
"primary key" 表示该列是表的主键, 本列的值必须唯一, MySQL将自动索引该列。
"auto_increment"表示该值若给的是NULL,则会自动的在当前最大值基础上加1赋值。
MySQL有3种数据类型:
数字类型
【tinyint(1字节-128~127),smallint,bigint,int(4字节最常用)(前面的都有unsigned),float(总长,小数长),double】,可在条件语句中比较大小
日期和时间类型
【year(2或4位),date(日期年-月-日=最常用),time(时间时:分:秒),datetime(日期和时间组合=最常用),timestamp(从1970.1.1开始的时间戳年月日时分秒无分割)】
字符串类型
【char(length定长字符串),varchar(length变长字符串=最常用),text(大量文本=最常用),blob(二进制对象如图片),enum(每局型只能是填入其中指定的值的索引)】
create table students
(
id int unsigned not null auto_increment primary key,
name char(8) not null,
sex char(4) not null,
age tinyint unsigned not null,
tel char(13) null default "-"
);
从sql脚本执行命令:
打开命令提示符, 输入:mysql -D samp_db -u root -p < createtable.sql
(提示: 1.如果连接远程主机请加上 -h 指令; 2. createtable.sql 文件若不在当前工作目录下需指定文件的完整路径。)crud是指在做计算处理时的增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写。crud主要被用在描述软件系统中数据库或者持久层的基本操作功能。
向表中插入数据【增】:
insert [into] 表名 [(列名1, 列名2, 列名3, ...)] values (值1, 值2, 值3, ...);
其中 [] 内的内容是可选的, 如给 samp_db 数据库中 students 表插入一条记录, 执行语句:
若是要完整插入一条记录insert into students values(NULL, "王刚", "男", 20, "13811371377");
,若是只插入部分数据或者不按照顺序插入数据则必须将列名和值一一对应插入:insert into students (name, sex, age) values("张三", "男", 20);
从表中【删】除符合条件的数据:
delete from 表名称 where 删除条件;
删除id为2的行: delete from students where id=2;
删除所有年龄小于21岁的数据: delete from students where age<20;
删除表中的所有数据: delete from students;更新修【改】表中的某条记录:
update 表名称 set 列名称=新值 where 更新条件;
将id为5的手机号改为默认的"-": update students set tel=default where id=5;
将所有人的年龄增加1: update students set age=age+1;
将手机号为 13288097888 的姓名改为 "张伟鹏", 年龄改为 19: update students set name="张伟鹏", age=19 where tel="13288097888";【替换REPLACE INTO】==【DELETE】+【INSERT INTO】:即先根据新插入值的主键查找,如果之前有这个主键存在则要DELETE该行然后在该位置替换新的一行数据;要是之前不存在该主键,那就在最后面插入一行新纪录。
replace into students (id,name,sex,age) values(1,"李四","男",30);
-
从表中【查】找数据:
select 列名称 from 表名称 [where查询条件获取指定的行] [order by 列名排序[ASC默认升序|DESC降序]] [LIMIT 限制输出从第几行开始的n条数据];
只查询 students 表中所有学生的名字和年龄两列内容:select name, age from students;
使用通配符 * 查询表中所有列的内容, 语句:select * from students;
查询返回不同的值过滤掉相同值【DISTINCT关键字】:select DISTINCT age from students;
只返回所有学生中不重复的年龄情况。
按特定条件查询: where 关键词用于指定查询条件:select 列名称 from 表名称 where 条件;
查询所有性别为女【字符串=】的信息:select * from students where sex="女";
查询年龄在21【数字比较大小】岁以上的所有人信息:select * from students where age > 21;
查询名字中带有 "王" 字【like】的所有人信息:select * from students where name like "%王%";
》》》通配符,注意%号表示匹配多个字符,_号表示匹配一个字符,如"王%"表示匹配姓王的名字,"王_"表示匹配姓王但是姓名只有两个字的人。这个比较总是不区分大小写的,若是使用binary关键字则可强制区分大小写where name binary like "A%"
表示匹配A开头的,而不会匹配a开头的。类似的还有一个【正则REGEXP】关键字,用于使用正则表达式匹配姓王的select * from students where name REGEXP "王$";
,所有的正则规则都可以使用。
查询id小于5且【and和or】年龄大于20的所有人信息:select * from students where id<5 and age>20;
查询年龄位于【between and】18到25的所有行:select * from students where age between 18 and 25;
找出年龄大于等于18岁的刚成年的年龄最小【order by】的5个人【limit】的信息:select * from students where age>=18 order by age ASC limit 0,5;
//即从小到大排序后下标0开始的5条记录
同上输出5个人后面接下来5个人的信息:select * from students where age>=18 order by age ASC limit 5,5;
//即从下标5开始的5条记录
使用【in】操作来指定想要匹配的范围列表(圆括号括起):where name in ("alice","bob","mary");
【多表查询】可以在一条select语句中查询两个无关联的表,假设fruit和color都有id和fruitname,colornamelainglie,各4行数据。若是直接select * from fruit,color;
则会展示4x4=16条记录,因为这个查询会简单的吧color表中的每一行追加连接到fruit后面。
select fruit.id,fruitname,colorname from fruit,color where fruit.id=color.id;
才会只输出4行数据。注意必须指明输出的id是谁的,如果直接用id会产生歧义报错。
【子查询,即语句中内含SELECT查询子句】select * from A where key in (select key from B)
就是求A表中key也在【配合IN使用】B表的所有A表的数据(不包含B表的数据)。和下图中A交B还是有区别的,A交B是指把A和B表中key相同的各列连接起来。
【join表联结】联结是在查询语句运行后对结果联结返回,不对数据库中的表进行修改。
select fruit.id,fruitname,colorname from fruit INNER JOIN color ON fruit.id=color.id;
可见使用ON代替了上面的where子句,【INNER JOIN】表示把两个表中id相同的行连接起来,默认只用【JOIN】就是指这个,【CROSS JOIN】从语法上来看在mysql与INNER JOIN等同,CROSS JOIN是交叉联结即类似全排列(笛卡尔积)。【STRAIGHT JOIN】完全等同于inner join 只不过,INNER JOIN语法是会自动根据“哪个表的结果集小,就以哪个表为驱动表”来决定谁先载入的,而straight_join 会强制选择其左边的表先载入。
前面讲的都是内联结,接下来看外联结。另外还有一个常用的【LEFT JOIN左联结】表示左边的表记录都会输出,ON后面匹配到的右边的表的内容才会连接到左表记录,没匹配的左表对应记录为空。同理【RIGHT JOIN右联结】表示右表记录全部输出,而左表只输出ON后匹配到的。
外键只是一个表中的非主键列但是它是另一个表的主键,即外面的主键的意思。用于将两个表关联起来,然后更好地进行联结查询或子查询。
要修改表结构(表的列值或表名称等):
添加列:alter table 表名 add 列名 列数据类型 [after 插入在哪列之后];
默认插入到末尾列
删除列:alter table 表名 drop 列名称;
修改列:alter table 表名 change 列名称 列新名称 新数据类型;
修改表名称:alter table 表名 rename 新表名;
删除表或者数据库:
删除表(在当前数据库操作范围内):drop table 表名;
删除数据库:drop database 数据库名;
4、mysql默认是不区分列名大小写的(输入的大写会先转为小写再保存),如何使字段查询区分大小写?
- 方法一:在sql查询条件语句中,要查询的字段前加
binary
关键字,表示使用二进制进行比较
SELECT * FROM emp WHERE BINARY emp.job='Engineer';
SELECT * FROM emp WHERE BINARY emp.job='ENGINEER'; - 方法二:在建表的时候就指定表中数据存储的格式,Mysql默认的字符检索策略:utf8_general_ci,表示不区分大小写;utf8_general_cs表示区分大小写,utf8_bin表示二进制比较,同样也区分大小写 。
创建表:
CREATE TABLE test(
id INT PRIMARY KEY,
name VARCHAR(32) NOT NULL //或者在后面直接指定BINARY二进制形式存储
) ENGINE = INNODB COLLATE =utf8_bin;
如果表已经创建,则修改表结构中Collation字段
- 在win操作系统,对数据库名和表名默认都不区分大小写,在linux下都区分。sql命令都不区分大小写。
在my.cnf文件中,有个变量值的设置可以影响表名称的大小写敏感,表示表名是否大小写敏感,可以修改。
lower_case_table_names = 0时,mysql会根据表名直接操作,大小写敏感,linux下默认设置。
lower_case_table_names = 1时,mysql会先把表名转为小写,再执行操作大小写就不敏感了。 - 命名规范
为了避免大小写引发的问题,一种推荐的命名规则是:在定义数据库/表/列的时候全部采用小写字母+下划线形式,不使用任何大写字母。
如果你使用InnoDB引擎,在任何平台上均应用lower_case_tables_name=1,以强制将名转换为小写。请注意在Unix系统中将lower_case_tables_name设置为1之前,重启mysqld之前,必须先将原来的数据库名以及表名全部转换为小写。
5、sql的查询优化原则?
- 根据存储引擎提供的统计信息,重新定义表的关联顺序;参考where语句和库表的结构设计,将外连接转换为内连接;使用等价变化规则,简化where过滤条件中的规则;将子查询转换为关联表;提前终止查询,如limit限制输出等;
- 在where的匹配条件中,如果要使用like和%_字符串匹配项,最好要放到最后,因为这个匹配起来最慢。
- 能使用MySQL的函数处理查询结果时尽量使用函数,比先查出来再在客户端进行处理效果更好,比如对查询出的所有订单的单价和数量求总价。
- 尽量避免子查询,而用join。
- 在使用Left (right) join的时候,一定要先在ON给出尽可能多的匹配满足条件,减少Where的执行。
- 尽量用INNER JOIN,避免 LEFT JOIN 和 NULL。
- 使用存储过程会比一条一条地执行更快。
- 如果不是真的需要所有列的数据,一般别用select *去查询,数据量很大时很慢。
- 索引能加快数据的查找,但是会使插入和删除数据性能降低,如果是频繁查找的数据更建议用索引。
- like很慢,不如使用FULLTEXT更快。
- 注意WHERE是在ON匹配产生的结果的基础上再过滤一遍。
mysql> SELECT * FROM product LEFT JOIN product_details
ON (product.id = product_details.id)
AND product_details.id=2;
+----+--------+------+--------+-------+
| id | amount | id | weight | exist |
+----+--------+------+--------+-------+
| 1 | 100 | NULL | NULL | NULL |
| 2 | 200 | 2 | 22 | 0 |
| 3 | 300 | NULL | NULL | NULL |
| 4 | 400 | NULL | NULL | NULL |
+----+--------+------+--------+-------+
rows in set (0.00 sec)
mysql> SELECT * FROM product LEFT JOIN product_details
ON (product.id = product_details.id)
WHERE product_details.id=2;
+----+--------+----+--------+-------+
| id | amount | id | weight | exist |
+----+--------+----+--------+-------+
| 2 | 200 | 2 | 22 | 0 |
+----+--------+----+--------+-------+
row in set (0.01 sec)
从上可知,第一条查询使用 ON 条件决定了从 LEFT JOIN的 product_details表中检索符合的所有数据行。
第二条查询做了简单的LEFT JOIN,然后使用 WHERE 子句从 LEFT JOIN的数据中过滤掉不符合条件的数据行。
6、数据库的备份和恢复?
- 备份命令mysqldump,主要是将当前数据库信息全部转为sql的insert语句保存起来
- 格式:
mysqldump -h主机名 -P端口 -u用户名 -p密码 –database 数据库名 > 文件名.sql
- 备份MySQL数据库某个(些)表
mysqldump -hhostname -uusername -ppassword databasename specific_table1 specific_table2 > backupfile.sql
- 备份服务器上所有数据库
mysqldump –all-databases > allbackupfile.sql
- 将数据库转移到新服务器
mysqldump -uusername -ppassword databasename | mysql –host=*.*.*.* -C databasename
- 常用source命令,用use进入到某个数据库,
mysql>source d:\test.sql
,后面的参数为脚本文件。 - 【增量备份】
小量的数据库可以每天进行完整备份,因为这也用不了多少时间,但当数据库很大时,就不太可能每天进行一次完整备份了,这时候就可以使用增量备份。增量备份的原理就是使用了mysql的binlog志。
1、首先做一次完整备份:
mysqldump -h10.6.208.183 -utest2 -p123 -P3310 --single-transaction --master-data=2 test>test.sql这时候就会得到一个全备文件test.sql
在sql文件中我们会看到:
-- CHANGE MASTER TO MASTER_LOG_FILE='bin-log.000002', MASTER_LOG_POS=107;是指备份后所有的更改将会保存到bin-log.000002二进制文件中。
2、在test库的t_student表中增加两条记录,然后执行flush logs命令。这时将会产生一个新的二进制日志文件bin-log.000003,bin-log.000002则保存了全备过后的所有更改,既增加记录的操作也保存在了bin-log.00002中。
3、再在test库中的a表中增加两条记录,然后误删除t_student表和a表。a中增加记录的操作和删除表a和t_student的操作都记录在bin-log.000003中。
- 【恢复数据】
1、首先导入全备数据
mysql -h10.6.208.183 -utest2 -p123 -P3310 < test.sql,也可以直接在mysql命令行下面用source导入
2、恢复bin-log.000002
mysqlbinlog bin-log.000002 |mysql -h10.6.208.183 -utest2 -p123 -P3310
3、恢复部分 bin-log.000003
在general_log中找到误删除的时间点,然后更加对应的时间点到bin-log.000003中找到相应的position点,需要恢复到误删除的前面一个position点。
可以用如下参数来控制binlog的区间
--start-position 开始点 --stop-position 结束点
--start-date 开始时间 --stop-date 结束时间
找到恢复点后,既可以开始恢复。
mysqlbinlog mysql-bin.000003 --stop-position=208 |mysql -h10.6.208.183 -utest2 -p123 -P3310
https://www.cnblogs.com/Cherie/p/3309456.html
7、数据库的3大范式?反范式?
1、第一范式
确保数据表中每列(字段)的原子性。
如果数据表中每个字段都是不可再分的最小数据单元,则满足第一范式。
例如:user用户表,包含字段id,username,password
例如:顾客表(姓名、编号、地址、……)其中"地址"列还可以细分为国家、省、市、区等。需要拆分成两个表:
顾客表——姓名、编号、地址ID
地址表——主键、国家、省份、市区
2、第二范式
在第一范式的基础上更进一步,目标是确保表中的每列都和主键相关。
如果一个关系满足第一范式,并且除了主键之外的其他列,都依赖于该主键,则满足第二范式。
例如:一个用户只有一种角色,而一个角色对应多个用户。则可以按如下方式建立数据表关系,使其满足第二范式。
user用户表,字段id,username,password,role_id
role角色表,字段id,name
用户表通过角色id(role_id)来关联角色表
3.第三范式
在第二范式的基础上更进一步,目标是确保表中的列都和主键直接相关,而不是间接相关。
例如:一个用户可以对应多个角色,一个角色也可以对应多个用户。则可以按如下方式建立数据表关系,使其满足第三范式。
user用户表,字段id,username,password
role角色表,字段id,name
user_role用户-角色中间表,id,user_id,role_id
像这样,通过第三张表(中间表)来建立用户表和角色表之间的关系,同时又符合范式化的原则,就可以称为第三范式。
4.反范式化
反范式化指的是通过增加冗余或重复的数据来提高数据库的读性能。
例如:在上例中的user_role用户-角色中间表增加字段role_name。
反范式化可以减少关联查询时,join表的次数。
8、常用的MySQL函数处理select查询的返回值?
-
select CONCAT(name,"+",school) AS stu from students;
拼接返回的多个列值。得到返回值如"bob+清华大学" - AS 关键字可以使经函数处理后的数据具有一个别名,然后就可以让客户端根据别名引用数据。如上stu就是拼接后的字符串列的别名。
- TRIM(name)/RTRIM()/LTRIM()用于对字段去除左右两边的空格。
- UPPER()/LOWER()转换成大写/小写。
- CURDATE()返回当前日期,CURTIME()返回当前时间,NOW()返回当前日期和时间。DATE(dt)和TIME(dt)是返回一个一个datetime类型数据的日期和时间部分。
- 直接在select后对各列返回值进行+-*/运行并取别名,可以得到结果列。
- 数值处理函数,如ABS()取绝对值,SQRT()取平方根,MOD()取余等。
- 对返回的某列的数据进行处理,COUNT(name)统计name列的行数,即name个数,
select COUNT(*) from students;
返回行数即学生个数而不是详细的每一行数据;MAX(age)返回最大age;MIN(age)返回最小age;AVG(age)返回平均age;SUM(age)返回所有年龄总和,`select SUM(price*quantity) as total_price from orderitems;就是先将单价和数量相乘再求和得到总价。 - DISTINCT 关键字用于将查询列值只返回不同的
- MATCH(note_text),AGAINST("hello world")函数组合使用,进行全文搜索。
9、分组查询GROUP BY?分组过滤HAVING(和where过滤的区别)?
- GROUP BY 子句必须出现在WHERE子句之后,ORDER BY子句之前。
注意上面的HAVING后的表达式必须写完整的而不能用上面的别名。
- SELECT+FROM+WHERE+GROUP BY+HAVING+ORDER BY+LIMIT;顺序
10、MySQL引擎的区别?
- 有两种,MyISAM和InnoDB,注意引擎是指的表的存储方式,而不是数据库的存储方式,同一个数据库中不同的表可以使用不同的引擎(创建表时再最后指定ENGINE=InnoDB),默认使用InnoDB。
- InnoDB支持事务,myisam不支持。
- mysiam支持全文索引FULLTEXT,innodb不支持。
- MyISAM:只支持表级锁,用户在操作myisam表时,select,update,delete,insert语句都会给表自动加锁,如果加锁以后的表满足insert并发的情况下可以在表的尾部插入新的数据。
InnoDB:支持事务和行级锁,是innodb的最大特色。行锁大幅度提高了多用户并发操作的性能。
但是InnoDB的行锁,只是在WHERE的主键是有效的,非主键的WHERE都会锁全表的。 - 表主键
MyISAM:允许没有任何索引和主键的表存在,索引都是保存行的地址。
InnoDB:如果没有设定主键或者非空唯一索引,就会自动生成一个6字节的主键(用户不可见),数据是主索引的一部分,附加索引保存的是主索引的值的数据列。 - MyISAM:如果执行大量的SELECT,MyISAM是更好的选择。
InnoDB:如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表。 - 外键
MyISAM:不支持
InnoDB:支持 - 存储空间
MyISAM:可被压缩,存储空间较小。支持三种不同的存储格式:静态表(默认,但是注意数据末尾不能有空格,会被去掉)、动态表、压缩表。
InnoDB:需要更多的内存和存储,它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引。
通过上述的分析,基本上可以考虑使用InnoDB来替代MyISAM引擎了,原因是InnoDB自身很多良好的特点,比如事务支持、更新数据更快、视图、存储过程、行级锁定等等,在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多。另外,任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。如果不是很复杂的Web应用,非关键应用,还是可以继续考虑MyISAM的,硬件资源有限也可以使用存储空间少的MyISAM,这个具体情况可以自己斟酌。
- 存储引擎选择的基本原则
采用MyISAM引擎
R/W > 100:1 且update相对较少
并发不高
表数据量小
硬件资源有限
采用InnoDB引擎
R/W比较小,频繁更新大字段
表数据量超过1000万,并发高
安全性和可用性要求高
采用Memory引擎
有足够的内存
对数据一致性要求不高,如在线人数和session等应用
需要定期归档数据
11、视图的使用?
- 视图是一种虚拟表,创建的规则和限制与表相似,但是注意视图不能索引,也不能有关联的触发器或默认值。
- 简单的视图可以更新底层表的这列数据,复杂的视图如有分组、联结、子查询、函数等的则不允许更新数据,因为可能底层就找不到这列数据。视图的主要作用还是用于查询数据,尽量不要用于更新数据。
12、存储过程?
- 存储过程,为以后使用而保存的一条或多条的SQL语句的组合,具有简单、安全和高性能的特点,和MySQL中函数相比,功能更加全面,使用简单,注意事项如下:
IN,使用时传递进去参数类型;OUT,存储过程使用后传递出去类型;
使用中需要使用delimiter暂时更新存储过程语句结束分割符,否则都使用默认的;会使得存储过程中的sql语句语法错误,如下先用//,在END结束存储过程的创建后又将分隔符设为默认的;号。
DELIMITER //
create procedure order_total(
IN order_num int,
OUT order_sum decimal(8,2)
)
BEGIN
select sum(item_price*quantity)
from orderitems where order_id = order_num
into order_sum;
END //
DELIMITER ;
// 调用这个存储过程
call order_total(1001,@total);
// 查看订单1001的结果:切记此处需要@
select @total;
//显示存储过程的创建语句
show CREATE PROCEDURE order_total;
// 删除过程:切记此处没有括号
dorp prodedure order_total;
//列出所有存储过程,包括显示何时由谁创建等信息。
show PROCEDURE STATUS; // LIKE "order_total"; 则是显示指定的存储过程的状态
13、触发器?
14、数据库的索引?
- 索引底层一般使用B+树实现的,将设为索引的一列值创建一个对应的B+树进行排序,然后就可以加快查询、排序的速度。
-
一般来说,应该在这些列上创建索引:
在经常需要搜索的列上,可以加快搜索的速度;
在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;
在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续;
在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。 - MyISAM使用B+Tree作为索引结构,索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。
- InnoDB也使用B+Tree作为索引结构,但具体实现方式却与MyISAM截然不同。第一个重大区别是InnoDB的数据文件本身就是索引文件。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。
15、创建索引的方式?
- 1、创建索引,例如 create index <索引的名字> on table_name (列的列表);
2、修改表,例如 alter table table_name add index[索引的名字] (列的列表);
3、创建表的时候指定索引,例如create table table_name ( [...], INDEX [索引的名字] (列的列表) ); - 查看表中索引的方法:
show index from table_name; 查看索引 - 删除索引
- 索引的类型及创建例子::
1.PRIMARY KEY (主键索引)
MySQL> alter table table_name add primary key (column
)
2.UNIQUE 或 UNIQUE KEY (唯一索引)
mysql> alter table table_name add unique (column
)
3.FULLTEXT (全文索引)
mysql> alter table table_name add fulltext (column
)
4.INDEX (普通索引)
mysql> alter table table_name add index index_name (column
)
5.多列索引 (组合索引)——最左前缀原则,即先匹配左边的列
mysql> alter tabletable_name
add index index_name (column1
,column2
,column3
)
16、sqlite3数据库和MySQL数据库的区别?
- sqlite是基于文件的数据库就是一个结构化的文件,程序只需要引用相应的C库函数就可以像读写文件一样访问该数据库,而不用像MySQL一样使用socket进程间通信,省掉了一次数据库远程链接没有复杂的权限验证,打开就能操作。
- sqlite数据库没有多用户管理,因此不支持多用户并发访问,该文件的访问权限只和文件的访问权限设置有关。
- 使用轻便快速,适合单机服务器使用数据量不超过百万无压力,sql语句大部分功能都兼容,有增有删。