一."SQL Server 不存在或访问被拒绝"
这个是最复杂的,错误发生的原因比较多,需要检查的方面也比较多.
一般说来,有以下几种可能性:
1,SQL Server名称或IP地址拼写有误
2,服务器端网络配置有误
3,客户端网络配置有误
要解决这个问题,我们一般要遵循以下的步骤来一步步找出导致错误的原因.
首先,检查网络物理连接
ping
如果 ping 不成功,说明物理连接有问题,这时候要检查硬件设备,如网卡,HUB,路由器等.
还有一种可能是由于客户端和服务器之间安装有防火墙软件造成的,比如 ISA Server.防火墙软件可能会屏蔽对 ping,telnet 等的响应
因此在检查连接问题的时候,我们要先把防火墙软件暂时关闭,或者打开所有被封闭的端口.
如果ping 成功而,ping 失败
则说明名字解析有问题,这时候要检查 DNS 服务是否正常.
有时候客户端和服务器不在同一个局域网里面,这时候很可能无法直接使用服务器名称来标识该服务器,这时候我们可以使用HOSTS文件来进行名字解析,
具体的方法是:
1.使用记事本打开HOSTS文件(一般情况下位于C:\WINNT\\drivers\etc).
添加一条IP地址与服务器名称的对应记录,如:
172.168.10.24
2.或在 SQL Server 的客户端网络实用工具里面进行配置,后面会有详细说明.
其次,使用 telnet 命令检查SQL Server服务器工作状态
telnet 1433
如果命令执行成功,可以看到屏幕一闪之后光标在左上角不停闪动,这说明 SQL Server 服务器工作正常,并且正在监听1433端口的 TCP/IP 连接
如果命令返回"无法打开连接"的错误信息,则说明服务器端没有启动 SQL Server 服务,
也可能服务器端没启用 TCP/IP 协议,或者服务器端没有在 SQL Server 默认的端口1433上监听.
接着,我们要到服务器上检查服务器端的网络配置,检查是否启用了命名管道.是否启用了 TCP/IP 协议等等
可以利用 SQL Server 自带的服务器网络使用工具来进行检查.
点击:程序 SQL Server 服务器网络使用工具
打开该工具后,在"常规"中可以看到服务器启用了哪些协议.
一般而言,我们启用命名管道以及 TCP/IP 协议.
点中 TCP/IP 协议,选择"属性",我们可以来检查 SQK Server 服务默认端口的设置
一般而言,我们使用 SQL Server 默认的1433端口.如果选中"隐藏服务器",则意味着客户端无法通过枚举服务器来看到这台服务器,起到了保护的作用,但不影响连接.
接下来我们要到客户端检查客户端的网络配置
我们同样可以利用 SQL Server 自带的客户端网络使用工具来进行检查,
所不同的是这次是在客户端来运行这个工具.
点击:程序 SQL Server 客户端网络使用工具
打开该工具后,在"常规"项中,可以看到客户端启用了哪些协议.
一般而言,我们同样需要启用命名管道以及 TCP/IP 协议.
点击 TCP/IP 协议,选择"属性",可以检查客户端默认连接端口的设置,该端口必须与服务器一致.
单击"别名"选项卡,还可以为服务器配置别名.服务器的别名是用来连接的名称,
连接参数中的服务器是真正的服务器名称,两者可以相同或不同.别名的设置与使用HOSTS文件有相似之处.
通过以上几个方面的检查,基本上可以排除第一种错误.
二."无法连接到服务器,用户xxx登陆失败"
该错误产生的原因是由于SQL Server使用了"仅 Windows"的身份验证方式,
因此用户无法使用SQL Server的登录帐户(如 sa )进行连接.解决方法如下所示:
1.在服务器端使用企业管理器,并且选择"使用 Windows 身份验证"连接上 SQL Server
2.展开"SQL Server组",鼠标右键点击SQL Server服务器的名称,选择"属性",再选择"安全性"选项卡
3.在"身份验证"下,选择"SQL Server和 Windows ".
4.重新启动SQL Server服务.
在以上解决方法中,如果在第 1 步中使用"使用 Windows 身份验证"连接 SQL Server 失败,
那就通过修改注册表来解决此问题:
1.点击"开始""运行",输入regedit,回车进入注册表编辑器
2.依次展开注册表项,浏览到以下注册表键:
[\\\\]
3.在屏幕右方找到名称"",双击编辑双字节值
4.将原值从1改为2,点击"确定"
5.关闭注册表编辑器
6.重新启动SQL Server服务.
此时,用户可以成功地使用sa在企业管理器中新建SQL Server注册,
但是仍然无法使用Windows身份验证模式来连接SQL Server.
这是因为在 SQL Server 中有两个缺省的登录帐户:
BUILTIN\
\ 被删除.
要恢复这两个帐户,可以使用以下的方法:
1.打开企业管理器,展开服务器组,然后展开服务器
2.展开"安全性",右击"登录",然后单击"新建登录"
3.在"名称"框中,输入 BUILTIN\
4.在"服务器角色"选项卡中,选择"System "
5.点击"确定"退出
6.使用同样方法添加 \ 登录.
说明:
以下注册表键:
\\\\\
的值决定了SQL Server将采取何种身份验证模式.
1.表示使用"Windows 身份验证"模式
2.表示使用混合模式(Windows 身份验证和 SQL Server 身份验证).
三.提示连接超时
如果遇到第三个错误,一般而言表示客户端已经找到了这台服务器,并且可以进行连接,
不过是由于连接的时间大于允许的时间而导致出错.
这种情况一般会发生在当用户在上运行企业管理器来注册另外一台同样在上的服务器,
并且是慢速连接时,有可能会导致以上的超时错误.有些情况下,由于局域网的网络问题,也会导致这样的错误.
要解决这样的错误,可以修改客户端的连接超时设置.
默认情况下,通过企业管理器注册另外一台SQL Server的超时设置是 4 秒,
而查询分析器是 15 秒(这也是为什么在企业管理器里发生错误的可能性比较大的原因).
具体步骤为:
企业管理器中的设置:
1.在企业管理器中,选择菜单上的"工具",再选择"选项"
2.在弹出的"SQL Server企业管理器属性"窗口中,点击"高级"选项卡
3.在"连接设置"下的"登录超时(秒)"右边的框中输入一个比较大的数字,如 20.
查询分析器中的设置:
工具 选项 连接 将登录超时设置为一个较大的数字
连接超时改为0
1、先保证ping通
2、在dos下写入telnet ip 1433不会报错
3、用ip连如企业管理器:
企业管理器>右键组>新建注册>下一步>写入远程实例名(IP,机器名)>下一步>选登陆>下一步>写入登陆名与密码(sa,pass)>下一步>下一步>完成
4、如果还不行:
服务器>开始菜单>>服务器网络实用工具>启用 WinSock代理>代理地址:(服务器IP)>代理端口>1433>OK了
5、如果还不行:
客户端>开始菜单>>客户端网络实用工具>别名>添加>写入别名如"大力">"网络库"选tcp/ip>服务器名称写入远程ip或实例名>OK了
深入解读MySQL InnoDB存储引擎Update语句执行过程
一丶Mysql整体架构#
MySQL 可以分为 Server 层和存储引擎层两部分
1.Server 层#
Server 层包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。
2.存储引擎层#
存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始成为了默认存储引擎。下面我们对比两个常用的存储引擎
MyISAM
InnoDB
存储结构
Myisam 创建表后生成的文件有三个,分别为: frm:创建表的语句 MYD:表里面的数据文件(myisam data) MYI:表里面的索引文件(myisam index)
Innodb 创建表后生成的文件有两个,分别为: frm:创建表的语句 idb:表里面的数据+索引文件
索引
非聚集索引,MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
聚集索引,聚集索引的文件存放在主键索引的叶子节点上
事务支持
不提供事务支持
提供事务支持
锁的粒度
只支持表级锁
支持行级锁。
存储表的具体行数
保存表的总行数,如果select count() from table;会直接取出出该值。
没有保存表的总行数,如果使用select count(*) from table;就会遍历整个表,消耗相当大,但是在加了wehre条件后,myisam和innodb处理的方式都一样。
以下的分析针对 update t set a='1' where 主键 = 1这条语句
二丶开启事务#
在mysql中,无论用户是否手动开启一个事务,sql都是在一个事务中进行的。我们可以使用start 开启一个事务,commit提交事务,回滚事务。
默认情况下,mysql存在自动提交(=1),这时候即使我们没有显式开启事务,直接执行update语句,那么mysql会隐式的开启一个事务,并在这条update执行结束后自动提交
如果set = 0 或者显式开启了一个事务,那么update执行结束后不会自动提交,而是需要手动发起commit 或者
无论式显式事务,还是隐式事务,mysql都会在事务内部第一次执行增删改操作的时候,给事务分配一个事务号
三丶Sql解析,查询计划生成#
mysql服务器层会从连接中读取sql语句,然后进行词法解析,语法解析,查询优化(为什么update语句需要查询优化?不查出来怎么知道修改哪些行数据昵)最终生成一个AST树,这便是物理执行计划,执行器会根据执行计划,调用存储引擎的接口,
四丶查询需要修改的数据#
Mysql InnoDB Buffer Pool
Mysql索引(究极无敌细节版
mysql innodb存储引擎对磁盘的读取是以页为单位的,为了避免每次都从磁盘读取数据,innodb存在buffer pool使用LRU链表维护最近访问到的页,为了更快的从buffer pool中查找到目标页,innodb 还使用表空间号和页号作为key,页作为value,形成Hash表。如果我们目标页已经在buffer pool中那么直接返回目标页,如果不在那么需要进行磁盘io加载目标页到内存,然后缓存到buffer pool中
1.buffer pool是如何维护页在内存中的#
buffer poo中存在三个关键的链表结构
2.怎么从16k的页中找到目标数据#
结合B+树索引结构,执行引擎根据页号找到根节点,然后根据根节点中的索引数据进行比较,找到子节点,重复此过程直至找到叶子节点所在的页。
到了叶子节点所在的页后,根据叶子节点页中的Page 中的槽找到目标记录所在的组,然后遍历这一组中的记录,找到目标记录。如果是范围查询,还需要根据B+树叶子节点间的双向指针继续查找,直到找到不符合要求的记录位置。(为了避免我们在遍历B+树的时候,其他线程修改了B+树的结构,此过程还需要对B+树进行加闩锁)(详细可看 Mysql索引(究极无敌细节版中的InnoDB索引方案一节)
五丶检验锁和加锁#
Mysql 锁
1.Mysql中的锁#innodb 行锁官方名称
记录锁有S锁和X锁,S型记录锁之间可以共享,X型记录锁和S型记录锁,X型记录锁互斥innodb的可重复读级别,使用词锁解决幻读问题,前面我们说过,其难点在于,加锁的时候幻影记录还未出现。官方使用实现如下操作
此处的gap锁可以反之其他事务在number为8记录前面的间隙插入新的记录,在区间(3,8)内无法进行插入操作,当另外一个事务要插入number为4的记录时,首先需要定位到该条记录的下一条记录,也就是number为8的记录,此时number为8的记录具备gap锁,所以将阻塞插入操作,直到gap锁被释放,其他事务才能进行插入。
gap锁出现的目的,就是为了防止插入幻影记录,如果对记录上gap锁,并不会限制其他事务对记录加记录锁。innodb有两个虚拟的记录Infimum(虚拟最小),(虚拟最大)当我们想在(xx,正无穷)范围锁住幻影记录时就可以对加gap锁。Next-Key Lock = 记录锁 + gap锁,既锁住记录,也锁住记录之前的间隙
插入意向锁,表示事务想在某个间隙插入新的记录,但是当前处于等待状态。比如事务A持有(4,8)范围内的gap锁,事务B和C,想插入(4,8)范围内的记录,就会在内存中生成事务B,C对应的插入意向锁,当前事务A释放gap锁的时候,将唤醒事务B和C,事务B和C可以同时获取插入意向锁,然后进行插入。插入意向锁并不会阻止对记录继续上锁。为事务生成内存中的锁结构并不是一个0成本的事情,为了节省这个成本,提出隐式锁的概念。当一个事务插入语一条记录A,其他事务select xxx Lock in share mode读取记录A(获取记录A的S锁),或者使用select xxx for update(获取记录A的X锁)立即修改记录A(获取x锁)对于聚簇索引来说,有一个隐藏列trx_id此列存储着最后更改记录的事务id,在当前事务A插入记录后,便是存储着当前事务A的id,其他事务B企图获取x锁,s锁的时候,就需要下先看一下,trx_id隐藏列对应的事务是否存活,如果不是那么正常获取,反之需要为当前事务A创建一个x锁内存结构,并标记为false,然后事务B将为自己创建一个锁结构, 为true然后事务B进入等待状态对于二级索引来说,其不具备隐藏列trx_id但是在二级索引页面的page header中的属性,记录了改动页面最大的事务id,如果其属性值小于当前最小的活跃事务id,那么说明对页面的改动事务已经提交,否则需要定位到二级索引记录,然后回表对聚簇索引进行上述聚簇索引的操作。一个事务对新插入的记录不需要显示的加锁,由于事务id的存在相当于加了一个隐式锁,别的事务需要加S锁或者X锁的时候,先帮之前的事务生成锁结构,然后为自己生成锁结构,再进入阻塞状态。隐式锁起到了延迟加锁的作用,也许别的事务不会获取于隐式锁冲突的锁,这时候可以减少内存中生成锁结构。2.一条Update语句涉及的锁#
2.1加共享元数据锁#
为了避免当前事务操作的时候,存在另外的用户对当前表进行DDL操作,mysql首先会为当前操作的表加共享元数据锁。这个过程可能存在阻塞的可能,如果当前事务企图加共享元数据锁的时候,存在另外一个事务正在对表进行DDL操作,这时候另外一个事务上了互斥元数据锁,这时候会出现当前事务阻塞的情况
2.2 加表级意向互斥锁#
此阶段也可能存在阻塞,但是由于innodb支持行锁,基本上很少有人给表上锁。如果执行当前事务之前存在另外一个事务给表上了表记共享锁,表记互斥锁,那么当前操作也会被阻塞。
加表记意向锁的好处在于,若没有意向锁,那么其他事务对表加锁的时候,需要遍历表中所有记录确保当前行中的记录没有被上锁
2.3 行锁#
innodb中的行锁,其实是在内存中,为当前行生成一个锁结构,记录事务id,索引信息,锁信息,锁类型等.如果当前事务加锁的时候,记录并没有加锁,那么会生成一个锁结构存储于内存中。如果锁已经被占用那么会挂起当前事务,直到锁被释放后唤醒当前事务。
六丶修改数据和生成日志#
在成功上锁之后,就可以放心的更新数据了,innodb将写三部分内容
1.写缓冲页#
不进行需要修改sql中指定的字段,还需要更新trx_id=当前事务的id, = 指向undo log
buffer pool中脏页的刷盘依赖于后台定时任务线程定时进行刷新,如果修改到此为止将存在数据丢失的问题,为此innodb存储引擎还需要写入以下两种日志
2.写undo log#
Mysql InnoDB多版本并发控制MVCC
undo log是为了记录行数据修改前的结果,用于回滚和mvcc。undo log 可以分为两种——记录insert undo log,和 update/delete undo log,生成的undo log会写入到undo log buffer。
2.1.mvcc#
如图多个版本的数据,在undo log中进行了记录,并且使用,进行串联,形成版本链。快照读查询语句执行前,或者使用start with (立即生成read view)会生成一个read view(一致性视图,如下)
read view包含如下几个字段
2.2如何利用一致性视图判断数据是否可见#如果被访问版本的trx_id和相同,意味着当前事务在访问自己修改的记录,自然可见如果访问版本的trx_id属性值小于read view中的 表明此版本是生成read view之前已经提交的事务,那么自然可见如果访问版本的trx_id,大于等于read view中的说明,当前版本数据是生成read view后开启事务产生的,那么自然不可见如果访问版本的trx_id 介于和之间,需要判断trx_id是否位于m_ids列表中,如果在说明创建read view时生成该版本的事务还是活跃的,那么该版本,不可被访问,如果不在说明创建read view 时生成该版本的事务已经提交,可以被访问到2.3Read 和 Read的不同#3.写redo log#
Mysql InnoDB Redo log
redo log 记录事务修改了哪个表空间(space id属性),哪个页(page number 属性),修改后的值(data属性)
即使是非常简单的一条变更sql,往往涉及到多出的改动,比如需改sql数据的字符数发生了变更,需要先删除,后插入。并且需要对上一条行记录的 属性进行修改,页中行数据的修改,往往同样需要修改page header,page 等内容,并且可能伴随着B+树节点分裂和合并。为了解决存在多种不同修改的问题,innodb存在多种类型的redo log。
3.1 mini-#
innodb 把一次变更分为多个mini-(MTR)一个MTR包含一组redo log,这一组redo log以一个特殊类型的redo log作为类型,恢复的时候,这一组redo log具备原子性,只有检测到特殊类型的redo log才任何一组redo log是完整的才会进行恢复(B+树叶子节点的分裂,不能说分裂一半)
3.2 log buffer#
生成redo log,会写入到log buffer,log buffer是一块连续的内存空间,由一个个大小为512B的log block组成,默认16mb大小。生成的redo log会找最小的一个redo log block 顺序写入
3.3 redo log 刷盘的时机:#事务提交log buffer 空间低于50%后台线程周期性刷盘mysql服务正常关闭做.4 redo log 进行崩溃恢复#
从位置开始读取redo log,来恢复脏页和undo log,然后通过undo log把所有未提交的事务的脏页进行回滚
七丶本地提交#
提交阶段 innodb存储引擎需要落盘redo log,mysql服务器层需要落盘binlog
1.binlog#
二进制逻辑日志,在逻辑备份和主备复制中发挥重要作用,具备三种格式
2.怎么保证binlog 和redo log状态一致#
mysql采用了内部XA事务的机制保证binlog,和redo log的状态顺序一致,通过两阶段提交的方式实现,两阶段提交存在一个协调者和多个参与者,在mysql中binlog是协调者,redo log是参与者
2.1mysql的两阶段提交#prepare阶段innodb刷redo log到磁盘,redo log刷盘完成后,修改事务状态为如果失败,那么事务会回滚,而prepare成功那么进入commit阶段commit阶段mysql服务器层写入binlog,写入完成后,修改事务状态为,表示事务已经成功提交2.2宕机的处理#3.redo log 和binlog 物理落盘策略#3.1 空置redo log的落盘#3.2 控制binlog的落盘#八丶主备复制#
主库写入binlog之后,备库的io线程会读取主库的binlog,并转存为本地的中继日志relay log,备库上的sql线程读取relay log并在本地执行
1.主备复制的策略#
不同的策略,其性能和一致性要求不同,也影响到主库能否返回
九丶返回提交成功#
至此mysql会给客户端返回成功
十丶脏页刷盘#
innodb后台有专门的线程负责将buffer pool中的脏页刷新到磁盘
如果后台线程刷新的很慢,且有新的页面需要进行缓存,这时候会从LRU链表尾部看看是否有可以直接释放的非脏页,如果不存在那么需要刷盘然后缓存新的页。
原文链接:
*请认真填写需求信息,我们会在24小时内与您取得联系。