调优过程
Posted 大叔聚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了调优过程相关的知识,希望对你有一定的参考价值。
性能调优 1 百胜表规范 USE ERP_DW GO /* 功能说明: 创建【区域】维度表 修改说明: Create by LY on 2011-09-07 */ IF EXISTS (SELECT 1 FROM SYSOBJECTS WHERE id = OBJECT_ID(\'Dim_Area\') AND type = \'U\') BEGIN DROP TABLE Dim_Area END GO CREATE TABLE [dbo].[Dim_Area] ( AreaCode VARCHAR(20) NOT NULL, AreaName VARCHAR(50) NULL, CONSTRAINT PK_DIM_AREA PRIMARY key (AreaCode) ); GO /* 功能说明: 获取区域表有效的信息 修改说明: Create by LY on 2011-09-07 */ IF EXISTS (SELECT 1 FROM SYSOBJECTS WHERE id = OBJECT_ID(\'VW_Dim_Area\') AND type = \'V\') BEGIN DROP VIEW VW_Dim_Area END GO CREATE VIEW VW_Dim_Area AS SELECT AreaCode FROM Dim_Area LEFT JOIN SYSOBJECTS ON 1=1 LEFT JOIN SYSCOLUMNS ON 1=1 WHERE 1=1 GROUP BY AreaCode GO /* 功能说明:抽取业务库的数据到数据仓库 修改说明: Create by LY on 2011-09-07 Modify by LY on 2011-09-07 增加变量的注释 */ IF EXISTS (SELECT 1 FROM SYSOBJECTS WHERE id = OBJECT_ID(\'P_GetData_Load_Dim_Area\') AND OBJECTPROPERTY(ID, N\'IsProcedure\') = 1) BEGIN DROP PROCEDURE [dbo].[P_GetData_Load_Dim_Area] END GO SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[P_GetData_Load_Dim_Area] @P_sourceDB_name NVARCHAR(50) ----源数据库名称,数据从哪抽取 AS BEGIN BEGIN TRAN ---开始事务 DECLARE @TrunSql VARCHAR(50); ----清空数据,不记录日志 DECLARE @InsertSql VARCHAR(MAX); ----插入数据 SET @TrunSql=\' TRUNCATE Table Dim_Area \'; EXEC (@TrunSql) IF @@error<>0 BEGIN ROLLBACK TRAN RETURN -1 END SET @InsertSql=\' INSERT INTO Dim_Area SELECT QUYU.QYDM as AreaCode, QUYU.QYMC as AreaName FROM ERP_Business..QUYU \'; EXEC(@InsertSql) IF @@ERROR<>0 BEGIN ROLLBACK TRAN RETURN -1 END COMMIT TRAN END; GO /* 功能说明:抽取业务库的数据到数据仓库 修改说明: Create by LY on 2011-09-07 Modify by LY on 2011-09-07 增加变量的注释 */ IF OBJECT_ID(\'[dbo].[P_GetData_Load_Dim_Area]\',\'P\') IS NOT NULL DROP PROC [dbo].[P_GetData_Load_Dim_Area] GO SET ANSI_NULLS ON SET QUOTED_IDENTIFIER ON GO CREATE PROCEDURE [dbo].[P_GetData_Load_Dim_Area] @P_sourceDB_name NVARCHAR(50) ----源数据库名称,数据从哪抽取 AS BEGIN BEGIN TRAN ---开始事务 DECLARE @TrunSql VARCHAR(50); ----清空数据,不记录日志 DECLARE @InsertSql VARCHAR(MAX); ----插入数据 SET @TrunSql=\' TRUNCATE Table Dim_Area \'; EXEC (@TrunSql) IF @@error<>0 BEGIN ROLLBACK TRAN RETURN -1 END SET @InsertSql=\' INSERT INTO Dim_Area SELECT QUYU.QYDM as AreaCode, QUYU.QYMC as AreaName FROM ERP_Business..QUYU \'; EXEC(@InsertSql) IF @@ERROR<>0 BEGIN ROLLBACK TRAN RETURN -1 END COMMIT TRAN END; 2 表分区 SQL Server引入的表分区技术,让用户能够把数据分散存放到不同的物理磁盘中,提高这些磁盘的并行处理性能以优化查询性能 2.1 表分区的介绍 表分区的作用,优点,步骤 (1)分区表的作用: 在大量业务数据处理的项目中,可以考虑使用分区表来提高应用系统的性能并方便数据管理,本文详细介绍了分区表的使 用。在大型的企业应用或企业级的数据库应用中,要处理的数据量通常可以达到几十到几百GB,有的甚至可以到TB级。虽然存储介质和数据处理技术的发展也很快,但是仍然不能满足用户的需求,为了使用户的大量的数据在读写操作和查询中速度更快,Oracle提供了对表和索引进行分区的技术,以改善大型应用系统的性能。 (2)使用分区的优点: 增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用; 维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可; 均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能; 改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。 (3).分区表的步骤: 1.创建分区函数 2.创建映射到分区函数的分区方案 3.创建使用该分区方案的分区表 2.2 表分区的SQL步骤 创建数据库的时候就创建分区的方案: use Master go /* 功能说明: 关闭数据库连接 修改说明: Create by LY on 2011-09-09 */ if object_id(\'Proc_KillDataBase\',\'P\') is not null drop proc Proc_KillDataBase go create proc Proc_KillDataBase @DataBaseName nvarchar(100) as begin DECLARE @i INT SELECT @i=1 DECLARE @sSPID VARCHAR(100) DECLARE KILL_CUR SCROLL CURSOR FOR SELECT SPID FROM sysprocesses WHERE DBID=DB_ID(@DataBaseName) OPEN KILL_CUR IF @@CURSOR_ROWS = 0 GOTO END_KILL_CUR FETCH FIRST FROM KILL_CUR INTO @sSPID EXEC( \'KILL \'+@sSPID) WHILE @i < @@CURSOR_ROWS BEGIN FETCH NEXT FROM KILL_CUR INTO @sSPID EXEC( \'KILL \'+@sSPID) SELECT @i=@i+1 END END_KILL_CUR: CLOSE KILL_CUR DEALLOCATE KILL_CUR end go EXEC Proc_KillDataBase \'PT_Sales\' GO /* 步骤一: 功能说明: 创建Sales数据库,创建多个文件组,用于数据分区 修改说明: Create by LY on 2011-09-09 */ IF EXISTS (SELECT 1 FROM sys.databases WHERE name = \'PT_Sales\') BEGIN DROP DATABASE PT_Sales END GO CREATE DATABASE PT_Sales ON PRIMARY -----------一个主文件,三个文件组,一个日志文件 ( NAME = N\'Sales\', FILENAME = N\'D:\\DB\\Sales.mdf\', SIZE = 3MB, MAXSIZE = 100MB, FILEGROWTH = 10% ), FILEGROUP FG1 ( NAME = N\'File1\', FILENAME = N\'D:\\DB\\PT\\File1.ndf\', SIZE = 1MB, MAXSIZE = 100MB, FILEGROWTH = 10% ), FILEGROUP FG2 ( NAME = N\'File2\', FILENAME = N\'D:\\DB\\PT\\File2.ndf\', SIZE = 1MB, MAXSIZE = 100MB, FILEGROWTH = 10% ), FILEGROUP FG3 ( NAME = N\'File3\', FILENAME = N\'D:\\DB\\PT\\File3.ndf\', SIZE = 1MB, MAXSIZE = 100MB, FILEGROWTH = 10% ) LOG ON ( NAME = N\'Sales_Log\', FILENAME = N\'D:\\DB\\Sales_Log.ldf\', SIZE = 1MB, MAXSIZE = 100MB, FILEGROWTH = 10% ) GO /* 步骤二: 功能说明: 建立分区函数,这里我们建立三个分区。how(如何对数据进行分区) 修改说明: Create by LY on 2011-09-09 */ USE PT_Sales GO CREATE PARTITION FUNCTION PT_OrderDate (datetime) AS RANGE RIGHT FOR VALUES (\'2003/01/01\', \'2004/01/01\') --n不能超过999,创建的分区数等于n + 1 GO /* 步骤三: 功能说明: 创建分区方案,关联到分区函数。where(在哪里对数据进行分区) 修改说明: Create by LY on 2011-09-09 */ USE PT_Sales GO CREATE PARTITION SCHEME PS_OrderDate AS PARTITION PT_OrderDate TO (FG1, FG2, FG3) GO /* 步骤四: 功能说明: 创建分区表。创建表并将其绑定到分区方案。这里我们建立个表,表的结构一样。 其中OrdersHistory表用于保存归档数据。 */ USE PT_Sales GO IF EXISTS (SELECT 1 FROM SYSOBJECTS WHERE id = OBJECT_ID(\'Orders\') AND type = \'U\') BEGIN DROP TABLE Orders END GO /*订单分区表*/ CREATE TABLE dbo.Orders ( OrderID int identity(10000,1), OrderDate datetime NOT NULL, CustomerID int NOT NULL, CONSTRAINT PK_Orders PRIMARY KEY (OrderID, OrderDate) ) ON PS_OrderDate (OrderDate) GO /*归档表【历史表】*/ IF EXISTS (SELECT 1 FROM SYSOBJECTS WHERE id = OBJECT_ID(\'OrdersHistory\') AND type = \'U\') BEGIN DROP TABLE OrdersHistory END GO CREATE TABLE dbo.OrdersHistory ( OrderID int identity(10000,1), OrderDate datetime NOT NULL, CustomerID int NOT NULL, CONSTRAINT PK_OrdersHistory PRIMARY KEY (OrderID, OrderDate) ) ON PS_OrderDate (OrderDate) GO USE PT_Sales GO INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES (\'2002/6/25\', 1000) INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES (\'2002/8/13\', 1000) INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES (\'2002/8/25\', 1000) INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES (\'2002/9/23\', 1000) INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES (\'2003/6/25\', 1000) INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES (\'2003/8/13\', 1000) INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES (\'2003/8/25\', 1000) INSERT INTO dbo.Orders (OrderDate, CustomerID) VALUES (\'2003/9/23\', 1000) GO SELECT * FROM dbo.Orders SELECT * FROM dbo.OrdersHistory /* 查看某一个分区 这里我们要用到$PARTITION 函数,这个函数可以帮助我们查询某个分区的数据, 还可以检索某个值所隶属的分区号。$PARTITION 函数的进一步细节可以查看MSDN 查询已分区表Order的第一个分区,代码如下: */ SELECT * FROM dbo.Orders WHERE $PARTITION.PT_OrderDate(OrderDate) = 2 /* 我们还可以查询某个分区有多少行数据,代码如下: */ SELECT $PARTITION.PT_OrderDate(OrderDate) AS Partition, COUNT(*) AS [COUNT] FROM dbo.Orders GROUP BY $PARTITION.PT_OrderDate(OrderDate) ORDER BY Partition ; /* 我们还可以通过$PARTITION 函数获得一组分区标示列值的分区号, 例如获得属于哪个分区,代码如下: 很明显,年隶属于第个分区,因为我们建立分区函数时用了RANGE RIGHT,所以返回。 你也可以把年换成,,,等等测试。你会发现,年属于第个分区, 2004年以后的都属于第个分区。 */ SELECT PT_Sales.$PARTITION.PT_OrderDate(\'2003\') /* 归档数据 假如现在是年年初,那么我们就可以把年所有的交易记录 归档到历史订单表HistoryOrder中。代码如下: */ USE PT_Sales GO ALTER TABLE dbo.Orders SWITCH PARTITION 1 TO dbo.OrdersHistory PARTITION 1 GO SELECT * FROM dbo.Orders SELECT * FROM dbo.OrdersHistory /* 便会发现,Orders 表只剩年的数据,而OrdersHistory表中包含了年的数据。 当然如果到了年年初,我们也可以归档年的所有交易数据。代码如下: */ USE PT_Sales GO ALTER TABLE dbo.Orders SWITCH PARTITION 2 TO dbo.OrdersHistory PARTITION 2 GO /* 添加分区: ALTER PARTITION SCHEME ps_OrderDate NEXT USED FG2 用来指定新分区的数据存储在那个文件。这里NEXT USED FG2 代表我们将新分区的数据保存在FG2文件组中,当然我们也可以在原有数据库上新建一个文件组,把新分区的数据保存在新文件组当中,这里我们直接用FG2文件组。 ALTER PARTITION FUNCTION pf_OrderDate() SPLIT RANGE (\'2005/01/01\') 代表我们创建一个新分区,而这里SPLIT RANGE (\'2005/01/01\')正是创建新分区的关键语法。 执行完上面的代码之后,我们就有了个分区,此时的区间如下: */ USE PT_Sales GO ALTER PARTITION SCHEME PS_OrderDate NEXT USED FG2 ALTER PARTITION FUNCTION PT_OrderDate() SPLIT RANGE (\'2005/01/01\') GO /* 删除分区: 删除分区又称为合并分区,假如我们想合并年的分区和年的分区到一个分区,我们可以用如下的代码: */ USE PT_Sales GO ALTER PARTITION FUNCTION PT_OrderDate() MERGE RANGE (\'2003/01/01\') GO /* 你会发现返回的结果是。而原来返回的是,原因是年以前数据所在的那个分区合并到了年这个分区中了。 假如此时我们执行如下代码: */ SELECT PT_Sales.$PARTITION.PT_OrderDate(\'2003\') /* 结果一行数据都没返回,事实就这样,因为OrdersHistory 表中只存储了 2002和年的历史数据,在没有合并分区之前,执行上面的代码肯定会 查询出年的数据,但是合并了分区之后,上面代码实际查询的是第二个分区中年的数据。 */ SELECT * FROM dbo.OrdersHistory WHERE $PARTITION.PT_OrderDate(OrderDate) = 2 /* 便会查询出行数据,包括年和年的数据,因为合并分区 后年和年的数据都成了第个分区的数据了。 */ SELECT * FROM dbo.OrdersHistory WHERE $PARTITION.PT_OrderDate(OrderDate) = 1 /* 查看源数据 */ select * from sys.partition_functions select * from sys.partition_range_values select * from sys.partition_schemes 2.3 将普通表转换成分区表 将普通表转换为分区表的做法 /* 功能说明:将普通表转换成分区表. 介绍: 在以上代码中,我们可以看出,这个表拥有一般普通表的特性——有主键,同时这个主键还是聚集索引。 前面说过,分区表是以某个字段为分区条件,所以,除了这个字段以外的其他字段,是不能创建聚集 索引的。因此,要想将普通表转换成分区表,就必须要先删除聚集索引,然后再创建一个新的聚集索 引,在该聚集索引中使用分区方案。 可惜的是,在SQL Server中,如果一个字段既是主键又是聚集索引时,并不能仅仅删除聚集索引。因此, 我们只能将整个主键删除,然后重新创建一个主键,只是在创建主键时,不将其设为聚集索引,如以下 代码所示: */ /* 功能说明:创建文件组 */ USE ERP_DW GO ALTER DATABASE ERP_DW ADD FILEGROUP [FG_ERP_DW_01] ALTER DATABASE ERP_DW ADD FILEGROUP [FG_ERP_DW_02] ALTER DATABASE ERP_DW ADD FILEGROUP [FG_ERP_DW_03] GO /* */ /* 功能说明:创建文件 */ ALTER DATABASE ERP_DW ADD FILE ( NAME = N\'FG_ERP_DW_01_data\', FILENAME = N\'D:\\DB\\PT\\FG_ERP_DW_01_data.ndf\', SIZE = 30MB, FILEGROWTH = 10% ) TO FILEGROUP [FG_ERP_DW_01]; ALTER DATABASE ERP_DW ADD FILE ( NAME=N\'FG_ERP_DW_02_date\', FILENAME=N\'D:\\DB\\PT\\FG_ERP_DW_02_data.ndf\', SIZE=30MB, FILEGROWTH=10% ) TO FILEGROUP以上是关于调优过程的主要内容,如果未能解决你的问题,请参考以下文章