数据库日志管理
1 日志的管理
SQL SERVER的日志达到一定程度时,会阻塞其它事务的处理,引起日志溢出的主要原因有:
1:系统管理人员没有及时清除日志。SQL SERVER在缺省值下,必须定期备份数据和日志,日志不能自动的清除。
2:由于执行非法的语句,如执行一条update语句,由于条件出错,导致无限量的产生日志,直到系统死机。
针对不同的错误原因,错误的严重性,采取不同的解决办法:
1:由小的事务引起日志溢出,系统能正常启动。
解决办法:
1.扩大数据库日志空间:
alter database 数据库名 on 设备名=数量(M为单位)
sp_logdevice 数据库名,设备名
2.清除日志
dump transaction 数据库名 with no_log(no_truncate)
2:由大的事物引起日志溢出,系统较长时间内无法正常启动或数据库无法恢复
解决办法:
1.等待。
较长的事务恢复时间较长,在无锡,有一次由于用户执行一条更新用户信息的SQL语句,由于使用错误的关联条件,导致日志溢出,恢复日志花了14小时。日志恢复完成后,一般系统就可正常运行。
2.强行清空日志。
在实在无法恢复数据库或有近期备份的情况下,可采用强行清空日志的方法。采取这种方法的后果有可能彻底破坏数据库。执行步骤如下:
Ⅰ 以-v 方式启动SQL SERVER(不检测日志)
Ⅱ 修改数据库状态为-32768(阻塞状态)
update sysdatabases set status=-32768 where name=数据库名
Ⅲ 授权sybase_ts_role权限(sybase_ts_role为SQL SERVER特殊管理员权限,在日常的数据库管理中,不需要这个角色)
sp_role “grant”,”sybase_ts_role”,sa
set role “sybase_ts_role”
Ⅳ 清除日志
dbcc rebuild_log(数据库名,1,1)
完成以上步骤后,重新启动SQL SERVER即可。如果数据库能正常启动,数据库就恢复完成;如果无法启动,只能重新创建数据库。
避免产生日志溢出的方法有:人工方法和自动方法。
人工方法:根据执行任务量的不同,定期备份日志和清除无用的日志,尽量增加日志可用的空间。优点:安全,数据库被破坏时,能恢复到上次备份的日志时为止。缺点:需人工操作,长时间不备份日志或执行非法的语句,有可能导致日志溢出。
自动方法:通过数据的阀值,可实时控制日志的溢出。优点:不会产生日志溢出。缺点:日志有可能会丢失,增大数据库处理的负担。阀值创建方法如下:
1:创建段
sp_addsegment 段名,数据库名,设备名
相关过程:sp_helpsegment,sp_dropsegment
2:创建阀值
sp_addthreshold 数据库名,段名,空闲空间,执行过程名
相关过程:sp_helpthreshold,sp_modifythreshold,sp_dropthreshold
创建阀值之后,当日志空闲空间达到阀值定义的空闲空间时,SERVER自动激活阀值定义的存储过程名。该存储过程对日志进行处理。以下以最简单的处理过程为例说明。
Create procedure sp_thresholdaction
@dbname varchar(30),
@segmentname varchar(30),
@space_left int,
@status int
as
dump transaction @dbname to tapedump1
print “LOG DUMP:’%1!’ for ‘%2!’ dumped”,@segmentname,@dbname
/* 备份日志到磁带,然后打印备份的段名,数据库名 */
2 一致性的检测
数据库如果经常非正常的shutdown可能引起数据的错误;长时间的运行有可能导致索引等错误。直接后果是运行速度明显下降、无法利用BCP备份数据(BCP执行结果错误)。此外还会影响物理空间的分配。数据库的检测可采用数据库提供的过程执行,最重要的一个过程如下:
1:dbcc checkcatalog(数据库名)
检查系统数据表中数据的一致性问题,如验证syscolumns表中的某个类型包含systypes表中的一行等。
2:dbcc checkdb(数据库名,skip_ncindex)
检查数据库中的每个表的空间分配情况,在数据转储时,可采用带skip_ncindex参数的方法加快表的检查速度。
3:dbcc checktable(表名)
检查每个表的分配信息,包含如下内容:页面连接、索引排序、指针的一致性、每页上的数据行在对象分配映射(OAM)页的入口。
4:dbcc checkalloc(表名|数据库名,full,nofix)
检查核实是否所有的页都被正确的分配,未分配的页是否也不是页面链的一部分,以及不属于页面链部分的页是否也未标记被分配了。除了对已分配的页面进行检查外,checkalloc也检查数据库中所有分配页,以确保它们包含有效的信息。
数据库损坏
SQL SERVER 6.5:
update sysdatabases set status = -32768 where name = ‘数据库名’
update sysdatabases set status = 12 where name = ‘数据库名’
dbcc checkdb(‘数据库名’)
dump transaction 数据库名 with no_log
数据库重启
SQL SERVER 7.0:
解决办法:
这是最简单的办法是有数据库的全备份,然后恢复即可.
步骤:
1. 删除原始的数据库:
USE MASTER
GO
DROP DATABASE DB_SUEPECT
2.建立同名的数据库:
USE master
GO
CREATE DATABASE DB_SUSPECT
ON
( NAME = DBNAME_DAT,
FILENAME = 'C:',
SIZE = 10,
FILEGROWTH = 5 )
LOG ON
( NAME = 'DBNAME_LOG',
FILENAME = 'g:',
SIZE = 5MB,
FILEGROWTH = 5MB )
GO
3.恢复数据库:
RESTORE DATABASE DB_SUSPECT
FROM DBNAME_BACKUP.DAT
4.数据库完整性检测:
DBCC CHECKDB('DB_SUSPECT')
5.重新启动MSSQLSERVER服务.
如果没有全备份,那就要用一些特殊的方法:
1.设置数据库为紧急模式
Use Master
GO
sp_configure 'allow updates', 1
reconfigure with override
GO
UPDATE sysdatabases SET status = 32768 where name = 'DB_SUSPECT'
GO
2.停掉SQL Server服务:
NET STOP MSSQLSERVER
3.把原始数据库的数据文件DBNAME_DAT.MDF,DBNAME_LOG.LDF移走:
4.启动SQL Server服务:
NET START MSSQLSERVER
5.重新建立一个同名的数据库DB_SUSPECT;
USE master
GO
CREATE DATABASE DB_SUSPECT
ON
( NAME = DBNAME_DAT,
FILENAME = 'C:',
SIZE = 10,
FILEGROWTH = 5 )
LOG ON
( NAME = 'DBNAME_LOG',
FILENAME = 'g:',
SIZE = 5MB,
FILEGROWTH = 5MB )
GO
6.设置数据库运行在单用户的模式:
USE MASTER
GO
ALTER DATABASE DB_SUSPECT SET SINGLE_USER
GO
7.停掉SQL服务:
NET STOP MSSQLSERVER
8.把原来的数据文件再覆盖回来:
9.启动SQL Server服务:
NET START MSSQLSERVER
10.重新设置SQLSERVER的状态:
USE MASTER
GO
EXEC sp_resetstatus "DB_SUSPECT"
11.数据库完整性检测:
DBCC CHECKDB('DB_SUSPECT')
12.恢复数据库为多用户模式:
USE MASTER
GO
ALTER DATABASE DB_SUSPECT SET MULTI_USER
GO
13.恢复SQLSERVER原始的配置:
USE MATER
GO
UPDATE sysdatabases SET status = 4194320 where name = 'DB_SUSPECT'
GO
14.配置SQLSERVER不允许更新系统表:
USE MASTER
GO
sp_configure 'allow updates', 0
reconfigure with override
GO
15.重新启动MSSQLSERVER服务:
最好重新启动操作系统
16.备份数据库:
可以通过SQLSERVER企业管理器或T-SQL.需要备份MASTER和DB_SUSPECT
ISQL奇怪现象
采用sqlserver 7.0 isql 在SQLSERVER 6.5服务器上使用:
isql –S –P –U –ixxx.sql
会存在执行脚本没完成,需手工按ctrl+c才能继续下去,加上 –c参数有些机器能解决,有些又不能。
后更换 sqlserver 6.5版本的isql.exe文件就可以成功。
SQL语句导入导出大全
导出到excel
EXEC master..xp_cmdshell 'bcp northwind.dbo.region out c:/temp1.xls -c -q –S"GNETDATA/GNETDATA" -U"sa" -P""'
导入Excel
SELECT *
FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0',
'Data Source="c:/test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0')...xactions
/*动态文件名
declare @fn varchar(20),@s varchar(1000)
set @fn = 'c:/test.xls'
set @s ='''Microsoft.Jet.OLEDB.4.0'',
''Data Source="'+@fn+'";User ID=Admin;Password=;Extended properties=Excel 5.0'''
set @s = 'SELECT * FROM OpenDataSource ('+@s+')...sheet1$'
exec(@s)
*/
SELECT cast(cast(科目编号 as numeric(10,2)) as nvarchar(255))+' ' 转换后的别名
FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0',
'Data Source="c:/test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0')...xactions
EXCEL导到远程SQL
insert OPENDATASOURCE(
'SQLOLEDB',
'Data Source=远程ip;User ID=sa;Password=密码'
).库名.dbo.表名 (列名1,列名2)
SELECT 列名1,列名2
FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0',
'Data Source="c:/test.xls";User ID=Admin;Password=;Extended properties=Excel 5.0')...xactions
导入文本文件
EXEC master..xp_cmdshell 'bcp dbname..tablename in c:/DT.txt -c -Sservername -Usa -Ppassword'
导出文本文件
EXEC master..xp_cmdshell 'bcp dbname..tablename out c:/DT.txt -c -Sservername -Usa -Ppassword'
或
EXEC master..xp_cmdshell 'bcp "Select * from dbname..tablename" queryout c:/DT.txt -c -Sservername -Usa -Ppassword'
导出到TXT文本,用逗号分开
exec master..xp_cmdshell 'bcp "库名..表名" out "d:/tt.txt" -c -t ,-U sa -P password'
dBase IV文件
select * from
OPENROWSET('MICROSOFT.JET.OLEDB.4.0'
,'dBase IV;HDR=NO;IMEX=2;DATABASE=C:/','select * from [客户资料4.dbf]')
dBase III文件
select * from
OPENROWSET('MICROSOFT.JET.OLEDB.4.0'
,'dBase III;HDR=NO;IMEX=2;DATABASE=C:/','select * from [客户资料3.dbf]')
FoxPro 数据库
select * from openrowset('MSDASQL',
'Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:/',
'select * from [aa.DBF]')
导入DBF文件
select * from openrowset('MSDASQL',
'Driver=Microsoft Visual FoxPro Driver;
SourceDB=e:/VFP98/data;
SourceType=DBF',
'select * from customer where country != "USA" order by country')
go
导出到DBF
如果要导出数据到已经生成结构(即现存的)FOXPRO表中,可以直接用下面的SQL语句
insert into openrowset('MSDASQL',
'Driver=Microsoft Visual FoxPro Driver;SourceType=DBF;SourceDB=c:/',
'select * from [aa.DBF]')
select * from 表
说明:
SourceDB=c:/ 指定foxpro表所在的文件夹
aa.DBF 指定foxpro表的文件名.
导出到Access
insert into openrowset('Microsoft.Jet.OLEDB.4.0',
'x:/A.mdb';'admin';'',A表) select * from 数据库名..B表
导入Access
insert into B表 selet * from openrowset('Microsoft.Jet.OLEDB.4.0',
'x:/A.mdb';'admin';'',A表)
文件名为参数
declare @fname varchar(20)
set @fname = 'd:/test.mdb'
exec('SELECT a.* FROM opendatasource(''Microsoft.Jet.OLEDB.4.0'',
'''+@fname+''';''admin'';'''', topics) as a ')
SELECT *
FROM OpenDataSource( 'Microsoft.Jet.OLEDB.4.0',
'Data Source="f:/northwind.mdb";Jet OLEDB:Database Password=123;User ID=Admin;Password=;')...产品
导入 xml 文件
DECLARE @idoc int
DECLARE @doc varchar(1000)
--sample XML document
SET @doc ='
<root>
<Customer cid= "C1" name="Janine" city="Issaquah">
<Order oid="O1" date="1/20/1996" amount="3.5" />
<Order oid="O2" date="4/30/1997" amount="13.4">Customer was very satisfied
</Order>
</Customer>
<Customer cid="C2" name="Ursula" city="Oelde" >
<Order oid="O3" date="7/14/1999" amount="100" note="Wrap it blue
white red">
<Urgency>Important</Urgency>
Happy Customer.
</Order>
<Order oid="O4" date="1/20/1996" amount="10000"/>
</Customer>
</root>
'
-- Create an internal representation of the XML document.
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- Execute a SELECT statement using OPENXML rowset provider.
SELECT *
FROM OPENXML (@idoc, '/root/Customer/Order', 1)
WITH (oid char(5),
amount float,
comment ntext 'text()')
EXEC sp_xml_removedocument @idoc
导整个数据库
用bcp实现的存储过程
实现数据导入/导出的存储过程,根据不同的参数,可以实现导入/导出整个数据库/单个表
调用示例:
--导出调用示例
----导出单个表
exec file2table 'zj','','','xzkh_sa..地区资料','c:/zj.txt',1
----导出整个数据库
exec file2table 'zj','','','xzkh_sa','C:/docman',1
--导入调用示例
----导入单个表
exec file2table 'zj','','','xzkh_sa..地区资料','c:/zj.txt',0
----导入整个数据库
exec file2table 'zj','','','xzkh_sa','C:/docman',0
*/
if exists(select 1 from sysobjects where name='File2Table' and objectproperty(id,'IsProcedure')=1)
drop procedure File2Table
go
create procedure File2Table
@servername varchar(200) --服务器名
,@username varchar(200) --用户名,如果用NT验证方式,则为空''
,@password varchar(200) --密码
,@tbname varchar(500) --数据库.dbo.表名,如果不指定:.dbo.表名,则导出数据库的所有用户表
,@filename varchar(1000) --导入/导出路径/文件名,如果@tbname参数指明是导出整个数据库,则这个参数是文件存放路径,文件名自动用表名.txt
,@isout bit --1为导出,0为导入
as
declare @sql varchar(8000)
if @tbname like '%.%.%' --如果指定了表名,则直接导出单个表
begin
set @sql='bcp '+@tbname
+case when @isout=1 then ' out ' else ' in ' end
+' "'+@filename+'" /w'
+' /S '+@servername
+case when isnull(@username,'')='' then '' else ' /U '+@username end
+' /P '+isnull(@password,'')
exec master..xp_cmdshell @sql
end
else
begin --导出整个数据库,定义游标,取出所有的用户表
declare @m_tbname varchar(250)
if right(@filename,1)<>'/' set @filename=@filename+'/'
set @m_tbname='declare #tb cursor for select name from '+@tbname+'..sysobjects where xtype=''U'''
exec(@m_tbname)
open #tb
fetch next from #tb into @m_tbname
while @@fetch_status=0
begin
set @sql='bcp '+@tbname+'..'+@m_tbname
+case when @isout=1 then ' out ' else ' in ' end
+' "'+@filename+@m_tbname+'.txt " /w'
+' /S '+@servername
+case when isnull(@username,'')='' then '' else ' /U '+@username end
+' /P '+isnull(@password,'')
exec master..xp_cmdshell @sql
fetch next from #tb into @m_tbname
end
close #tb
deallocate #tb
end
go