SQLServer性能优化

SQLServer语句执行顺序

  • 步骤1. FROM <left_table>
    FROM子句,组装来自不同数据源的数据,对FROM子句中前后两表执行笛卡尔积生成虚拟表vt1
  • 步骤2. ON <join_condition>
    对虚拟表vt1应用ON筛选器,只有满足<join_condition>连接条件为真时才被插入新虚拟表vt2
  • 步骤3. <join_type> JOIN <right_table>
    如果指定了OUTER JOIN保留表(preserved table)中未找到的行,将行作为外部行添加到新的虚拟表vt2并生成新虚拟表vt3
    如果FROM子句中包含两个以上的表,则对上一个连接生成的结果表和下一个表重复执行步骤1和步骤2,直到结束。
  • 步骤4. WHERE <where_condition>
    对虚拟表vt3应用WHERE筛选器,只有<where_condition>条件为真的行才能被插入新的虚拟表vt4
  • 步骤5. GROUP BY <group_by_list>
    GROUP BY子句中的列对虚拟表vt4中的行进行分组并生成新的虚拟表vt5
  • 步骤6. WITH {cube | rollup}
    将超组(super groups)插入到新生成的虚拟表vt6
  • 步骤7. HAVING <having_condition>
    对虚拟表vt6应用HAVING筛选器,当<having_condition>条件为真的组才被插入到虚拟表vt7
  • 步骤8. SELECT
    处理SELECT列列表并生成虚拟表vt8
  • 步骤9. DISTINCT
    将虚拟表vt8中重复的行剔除后生成虚拟表vt9
  • 步骤10. ORDER BY <order_by_list>
    将虚拟表vt9的行,按ORDER BY子句中的列列表排序生成游标vc10
  • 步骤11. TOP <top_specification> <select_list>
    从游标vc10的开始处选择指定数量或比例的行生成虚拟表vt11并返回调用者。

优化子查询

WITH+ EXISTS

对存在子查询的语句,可使用WITH...AS优化替换,原则上是尽可能避免子查询。
对于IN操作的语句,应尽量使用EXISTS 替换 IN

-- 原始语句
SELECT * 
FROM WHGameUserDB.dbo.UserAccount 
WHERE 1=1 
AND ChannelID IN(SELECT ChannelID FROM WHTreasureDB.dbo.ChannelConfig WHERE ChannelType=1)

-- 优化替换
WITH tbl(ChannelID) AS (
    SELECT ChannelID FROM WHTreasureDB.dbo.ChannelConfig WHERE ChannelType=1
)

SELECT * 
FROM WHGameUserDB.dbo.UserAccount t1 
WHERE 1=1 
AND EXISTS(SELECT 1 FROM tbl WHERE ChannelID=t1.ChannelID)

优化连表查询

JOIN链接最好不要超过5张表,若存在更新的大数据表,应先放进临时表,然后再使用JOIN连接。

SELECT Channel,PlayDate,Score,UserID INTO #tmp FROM WHTreasureDB.dbo.GameRecordMain WHERE 1=1 AND ClubID=53297316

-- 使用临时表替换大表直接连接
SELECT Channel,PlayDate,Score,UserID INTO #tmp FROM WHTreasureDB.dbo.GameRecordMain WHERE 1=1 AND ClubID=53297316
SELECT * FROM WHGameUserDB.dbo.UserAccount t1, #tmp WHERE 1=1 AND t1.UserID=#tmp.UserID
DROP TABLE #tmp

查看语句执行信息

-- 设置查看语句影响行数
SET NOCOUNT OFF
-- 设置查看执行时间和CPU占用时间
SET STATISTICS TIME ON
-- 设置查询对IO的操作情况
SET STATISTICS IO ON

-- TEST
SELECT * FROM dbo.PropConfig
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

(6 行受影响)
Table 'PropConfig'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.

查询正在执行的语句

注意:SqlServer数据库时间以微秒为单位,即1秒=1000毫秒(ms)=1000*1000微秒。

SET NOCOUNT OFF;
SET STATISTICS TIME ON;
SET STATISTICS IO  ON;

-- 查询正在执行的语句
SELECT TOP 10   
    st.text AS [执行语句]                 
    ,qs.execution_count [执行次数] 
    ,qs.creation_time AS [执行时间] 
    ,(qs.total_logical_reads + qs.total_logical_writes) AS [逻辑读写]
    ,qs.total_logical_reads AS [逻辑读取]
    ,qs.total_logical_writes AS [逻辑写入]
    ,qs.total_physical_reads [物理读取]
    ,qs.total_elapsed_time AS [执行耗时]
    ,qs.total_worker_time AS [CPU耗时]
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st
ORDER BY qs.creation_time DESC

查询当前缓存中批处理或存储过程占用CPU资源的情况

-- 查询当前缓存中批处理或存储过程占用CPU资源的情况
SELECT TOP 50   
    qs.sql_handle
    ,COUNT(*) AS [语句个数]
    ,SUM(qs.execution_count) AS [执行次数]
    ,SUM(qs.total_worker_time)/1000.0 AS [CPU耗时]
    ,SUM(qs.total_elapsed_time)/1000.0 AS [执行耗时]
    ,SUM(qs.total_logical_reads) AS [逻辑读取]
    ,SUM(qs.total_logical_writes) AS [逻辑写入]
    ,SUM(qs.total_physical_reads) AS [物理读取]
FROM sys.dm_exec_query_stats AS qs
GROUP BY qs.sql_handle
ORDER BY 4 DESC

查询执行耗时的语句

--查询执行耗时的语句
SELECT 
    SS.sum_execution_count
    ,SS.sum_total_elapsed_time
    ,SS.sum_total_worker_time
    ,SS.sum_total_logical_reads
    ,SS.sum_total_logical_writes  
    ,T.text
FROM (
    SELECT 
        S.plan_handle
        ,SUM(S.execution_count) sum_execution_count
        ,SUM(S.total_elapsed_time) sum_total_elapsed_time
        ,SUM(S.total_worker_time) sum_total_worker_time
        ,SUM(S.total_logical_reads) sum_total_logical_reads
        ,SUM(S.total_logical_writes) sum_total_logical_writes
    FROM SYS.dm_exec_query_stats S
    GROUP BY S.plan_handle
) AS SS
CROSS APPLY SYS.dm_exec_sql_text(SS.plan_handle) T
ORDER BY sum_total_logical_reads DESC

查询CPU消耗最高的SQL语句

--查询CPU消耗最高的SQL语句
SELECT TOP 10 
    TEXT AS [SQL]
    ,last_execution_time AS [最后执行时间]
    ,(total_logical_reads + total_physical_reads + total_logical_writes) / execution_count AS [IO平均读写次数]
    ,(total_worker_time / execution_count) / 1000000.0 AS [CPU平均执行秒数]
    ,(total_elapsed_time / execution_count) / 1000000.0 AS [平均执行秒数]
    ,execution_count AS [执行次数]
    ,qs.total_physical_reads AS [物理读取次数]
    ,qs.total_logical_writes AS [逻辑写入次数]
    ,qp.query_plan AS [查询计划]
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) st
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY total_elapsed_time / execution_count DESC

查找执行次数最多的SQL语句

--查找执行次数最多的SQL语句
DECLARE @begin_time DATETIME = '2018-01-01 00:00:00';
DECLARE @execute_count_limit INT = 500;

WITH tbl AS (
    SELECT  
        --执行次数 
        QS.execution_count 
        ,SUBSTRING(
            ST.text
            ,(QS.statement_start_offset / 2) + 1
            ,((CASE QS.statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE QS.statement_end_offset END - QS.statement_start_offset)/2) + 1 
        ) AS statement_text
        ,ST.text AS [text]
        ,QS.last_elapsed_time
        ,QS.min_elapsed_time
        ,QS.max_elapsed_time
        ,QS.total_worker_time
        ,QS.last_worker_time
        ,QS.max_worker_time
        ,QS.min_worker_time 
    FROM sys.dm_exec_query_stats QS 
    CROSS APPLY sys.dm_exec_sql_text(QS.sql_handle) ST 
    WHERE 1=1
    AND QS.last_execution_time > @begin_time
    AND QS.execution_count > @execute_count_limit
    --AND ST.text LIKE '%%' 
    --ORDER BY QS.execution_count DESC
)

SELECT 
    MAX(execution_count) max_execution_count
    ,[text]
FROM tbl
WHERE 1=1 
AND [text] NOT LIKE '%sp_MSupd_%' 
AND [text] NOT LIKE '%sp_MSins_%' 
AND [text] NOT LIKE '%sp_MSdel_%' 
GROUP BY [text]
ORDER BY 1 DESC

查找逻辑读取最高的存储过程

--查找逻辑读取最高的查询(存储过程)
SELECT TOP 25 
    p.name AS [存储过程]
    ,deps.total_logical_reads AS [逻辑读总次数] 
    ,deps.total_logical_reads / deps.execution_count AS [逻辑读平均次数]
    ,deps.execution_count [总执行次数]
    ,ISNULL(deps.execution_count / DATEDIFF(Second, deps.cached_time, GETDATE()), 0) AS [每秒调用次数] 
    ,deps.total_elapsed_time/1000/1000.0 AS [总消耗时长]
    ,deps.total_elapsed_time/1000/1000.0/deps.execution_count AS [平均消耗时长]
    ,deps.cached_time AS [缓存时间]
FROM sys.procedures AS p
INNER JOIN sys.dm_exec_procedure_stats AS deps ON p.[Object_id] = deps.[Object_id]
WHERE 1=1
AND deps.Database_id = DB_ID()
ORDER BY deps.total_elapsed_time DESC;

数据库性能优化

-- 排查历史慢查询
SELECT TOP 50
    DB_NAME(qt.dbid) AS [数据库]
    ,OBJECT_NAME(qt.objectid, qt.dbid) AS [对象名]
    ,qs.creation_time AS [创建时间]
    ,qs.last_execution_time AS [最近执行时间]
    ,qs.last_elapsed_time AS [最近执行耗时]
    ,qs.last_worker_time AS [最近CPU耗时]
    ,qs.last_rows AS [最近影响行数]
    ,qs.execution_count AS [执行次数]
    ,qs.total_elapsed_time AS [累计执行耗时]
    ,(qs.total_elapsed_time / qs.execution_count) AS [平均执行耗时]
    ,qs.max_elapsed_time AS [最大执行耗时]
    ,qs.total_worker_time AS [累计CPU耗时]
    ,(qs.total_worker_time / qs.execution_count) AS [平均CPU耗时]
    ,qs.max_worker_time AS [最大CPU耗时]
    ,(qs.total_logical_reads + qs.total_logical_writes) AS [累计逻辑读写]
    ,(qs.total_logical_reads + qs.total_logical_writes)/qs.execution_count AS [平均逻辑读写]
    ,qs.min_rows AS [最小影响行数]
    ,qs.max_rows AS [最大影响行数]
    ,qs.total_rows AS [累计影响行数]
    ,SUBSTRING(
        qt.text,
        (qs.statement_start_offset/2) + 1,     
        ((
        CASE WHEN qs.statement_end_offset = -1
        THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
        ELSE qs.statement_end_offset
        END - qs.statement_start_offset
        )/2) + 1
    ) AS [独立查询]
    ,qt.text AS [父级查询]
    ,qp.query_plan AS [查询计划]
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE 1=1
AND qt.dbid IS NOT NULL
AND DB_NAME(qt.dbid)!='msdb'
ORDER BY 4 DESC

-- 精简版 
SELECT TOP 100
    DB_NAME(qt.dbid) AS [数据库]
    ,OBJECT_NAME(qt.objectid, qt.dbid) AS [对象名]
    ,qs.execution_count AS [执行次数]
    ,qs.total_worker_time/1000/1000 AS [CPU总消耗秒数]
    ,qs.total_worker_time/qs.execution_count/1000/1000.0 AS [CPU平均消耗秒数]
    ,max_worker_time/1000/1000.0 AS [CPU最大消耗秒数]
    ,SUBSTRING(
        qt.text
        ,qs.statement_start_offset/2+1
        ,(CASE WHEN qs.statement_end_offset = -1 THEN DATALENGTH(qt.text) ELSE qs.statement_end_offset END -qs.statement_start_offset)/2 + 1
    ) AS [剔除注释]
    ,qt.text [完整语句]
    ,last_execution_time AS [最后执行时间]
FROM sys.dm_exec_query_stats qs 
WITH(NOLOCK) CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt
WHERE 1=1
AND qs.execution_count > 0 
-- AND qs.total_worker_time/qs.execution_count/1000 > 1
AND OBJECT_NAME(qt.objectid, qt.dbid) IS NOT NULL
AND DB_NAME(qt.dbid) != 'msdb'
ORDER BY qs.execution_count DESC

The user does not have permission to perform this action.

排查历史慢查询

建议先优化慢查询,然后根据IOPS、QPS、CPU等指标决定是否升级实例规格。

--排查历史慢查询
SELECT TOP 50
    (qs.total_logical_reads + qs.total_logical_writes) AS [逻辑读写]
    ,(qs.total_logical_reads + qs.total_logical_writes)/qs.execution_count AS [平均读写]
    ,qs.execution_count AS [执行次数]
    ,SUBSTRING(
        qt.text,
        (qs.statement_start_offset/2) + 1,     
        ((
        CASE WHEN qs.statement_end_offset = -1
        THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
        ELSE qs.statement_end_offset
        END - qs.statement_start_offset
        )/2) + 1
    ) AS [独立查询]
    ,qt.text AS [父级查询]
    ,DB_NAME(qt.dbid) AS [数据库]
    ,qp.query_plan AS [查询计划]
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE 1=1
AND qt.dbid IS NOT NULL
AND DB_NAME(qt.dbid)!='msdb'
ORDER BY 2 DESC

查询当前正在执行的慢查询

-- 查询当前正在执行的慢查询
SELECT TOP 10
    ST.transaction_id AS TransactionID
    ,ST.session_id
    ,DB_NAME(DT.database_id) AS DatabaseName
    ,SES.host_name
    ,SES.login_name
    ,SES.status
    ,AT.transaction_begin_time AS TransactionStartTime
    ,S.text 
    ,C.connect_time 
    ,DATEDIFF(second, AT.transaction_begin_time, GETDATE()) "exec_time(s)" 
    ,DATEDIFF(minute, AT.transaction_begin_time, GETDATE()) AS Tran_run_time
    ,CASE AT.transaction_type
    WHEN 1 THEN 'Read/Write Transaction'
    WHEN 2 THEN 'Read-Only Transaction'
    WHEN 3 THEN 'System Transaction'
    WHEN 4 THEN 'Distributed Transaction'
    END AS TransactionType 
    ,CASE AT.transaction_state
    WHEN 0 THEN 'Transaction Not Initialized'
    WHEN 1 THEN 'Transaction Initialized & Not Started'
    WHEN 2 THEN 'Active Transaction'
    WHEN 3 THEN 'Transaction Ended'
    WHEN 4 THEN 'Distributed Transaction Initiated Commit Process'
    WHEN 5 THEN 'Transaction in Prepared State & Waiting Resolution'
    WHEN 6 THEN 'Transaction Committed'
    WHEN 7 THEN 'Transaction Rolling Back'
    WHEN 8 THEN 'Transaction Rolled Back'
    END AS TransactionState
FROM sys.dm_tran_session_transactions AS ST
INNER JOIN sys.dm_tran_active_transactions AS AT ON ST.transaction_id = AT.transaction_id
INNER JOIN sys.dm_tran_database_transactions AS DT ON ST.transaction_id = DT.transaction_id
LEFT JOIN sys.dm_exec_connections AS C ON st.session_id = C.session_id
LEFT JOIN sys.dm_exec_sessions AS SES ON C.session_id = SES.session_id
CROSS APPLY sys.dm_exec_sql_text(C.most_recent_sql_Handle) S
WHERE 1=1
AND DATEDIFF(second, AT.transaction_begin_time, GETDATE()) > 2

查询最近修改的存储过程

SELECT 
  Name
  ,Create_date
  ,Modify_Date 
FROM sys.objects 
WHERE 1=1
AND TYPE in ('U','P', 'V','F', 'TR', 'FN') 
ORDER BY Modify_Date DESC;

查询每秒死锁数量

--查询每秒死锁数量
SELECT *
FROM sys.dm_os_performance_counters
WHERE 1=1
AND counter_name LIKE 'Number of Deadlocksc%';

通过等待类型分析耗时操作

--查询等待类型
SELECT TOP 10 * FROM SYS.dm_os_wait_stats ORDER BY wait_time_ms DESC
--通过等待类型分析耗时操作 

查看内存结构

SELECT
    (physical_memory_in_use_kb/1024) AS MemoryUsed
    ,(locked_page_allocations_kb/1024) AS LockedPagesUsed
    ,(total_virtual_address_space_kb/1024) AS VASTotal
    ,process_physical_memory_low
    ,process_virtual_memory_low 
FROM sys.dm_os_process_memory;

查看数据库连接数

SELECT 
* 
FROM sysprocesses 
WHERE 1=1
AND dbid IN(SELECT dbid FROM sysdatabases WHERE 1=1 AND name='WHGameUserDB') 

检索索引碎片

SELECT  
    DB_NAME(ps.database_id) AS [DbName] 
    ,OBJECT_NAME(ps.OBJECT_ID) AS [DbObject]
    ,ps.index_id AS [IndexID]
    ,b.name 
    ,ps.avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS ps
INNER JOIN sys.indexes AS b ON ps.OBJECT_ID = b.OBJECT_ID AND ps.index_id = b.index_id
WHERE 1=1
AND ps.database_id = DB_ID('ReportServerTempDB')
ORDER BY ps.avg_fragmentation_in_percent DESC
SQLServer安全及性能优化 修补漏洞 安装程序补丁修补漏洞 随时关注微软官方网站补丁升级 关闭不必要的端口 关闭联必要的服务 数据库引擎 SQL Server Analysis Services SQL Server Reporting Services SQL Server Integration Services SQL Server 代理 SQL Full-text Filter Daemon launcher SQL Server Browser 同时开启所有服务系统性能会变得很差,根据需要手动启动或者禁用某个服务 DTC: Distributed Transaction Coordinator(分布式事务处理协调器),用于协调多个数据库、消息队列、文件系统等等资源管理器的事务,由于内部开发中并不使用这个功能,远程数据库服务器上也并不经常使用,因此建议关闭这个服务 禁用不使用的协议 Shared Memory 默认为已启用状态,这个协议只能用于本地连接,不能用于远程连接,一般用于其它协议出问题的时候管理作诊断使用 TCP/IP 禁用不需要使用的协议,减少网络攻击对象 减少监听的网卡和IP地址 改变监听端口号 安全地设置账户 Windows身份验证[微软推荐的方式] 优势: 1.访问SqlServer时速度更快,不用输入用户名和密码 2.可以利用Windows系统的自身工具和安全策略管理账户 3.安全确认和口令加密、审核、口令失效、最小口令长度和账号锁定 SqlServer身份验证 1.将sa账户名更改为其它账户名比如nocial,防止黑客利用sa进行攻击 2.删除不使用的账户 3.对已有账户设置安全密码[强制密码规则] 4.限制登录->远程登录、匿名登录 5.限制用户角色和权限,一般将权限设置到最低。设置角色的时候不要为public角色授予任何权限,并且从sysadmin这个角色中删除windows的administrators组,提高系统安全性。 删除不必要的数据库对象 删除危险的存储过程 xp_cmdshell:执行操作系统命令,这是一个系统后门[可以移动文件位置、创建用户、提升用户权限],建议不需要则删除掉。 ole自动化存储过程 任务管理存储过程 强化文件和目录安全 数据库最终以文件的形式存储在文件系统中 使用NTFS设置权限 限制共享【不能设置为完全控制】 及时审核日志 sqlserver的审核机制可以帮助跟踪并且阻止系统中没有授权的用户他的行为。比如没有授权的用户登录系统会阻止这次登录,并且把这次操作给记录下来。审核机制既能跟踪失败记录也能跟踪成功记录。所有的数据库平台均在不同程度上提供了审查功能。 跟踪用户行为 保护数据库 数据库性能优化 数据库的性能优化主要有两个方面:减少查询比较次数、减少资源的征用。 使用工具Sql Server Profiler优化数据库的性能,减少资源的征用 SqlServer Profiler的功能 Sql Server Profiler的用法  定义跟踪  登录连接、失败和断开  Select、Insert、Update和Delete语句  SQL批处理的开始或结束  写入到Sql server错误日志的错误  安全权限检查  Profiler执行的事件 让Profiler监视我们感兴趣的事件,可以监视的事件太多,监视太多会大大降低性能和增大表数据,只监视与数据库的性能密切相关的哪些事件。常见的感兴趣的事件:  执行查询的性能  单个用户或应用程序的活动  逻辑磁盘的读写  语句级别上的CPU占用  Standart模板的事件类 优化数据库性能可以从五个层次来进行:  优先级一:减少数据的访问【减少磁盘访问】  优先级二:返回更少数据【减少网络传输或磁盘访问】  优先级三:减少交互次数【减少网络传输或磁盘访问】  优先级四:减少开销【减少CPU及内存开销】  优先级五:利用更多资源【增加资源】 技术上从四个方面来解决性能优化问题 1、调整数据库结构设计 2、调整应用程序结构设计 3、调整数据库SQL语句 4、调整服务器内存分配 如果不熟悉sqlserver可以使用数据库引擎优化顾问来对数据库提出优化建议,然后通过系统管理的修改达到目的。 数据库引擎优化顾问  数据库引擎优化顾问介绍  分析一个或多个数据库的工作负荷和物理实现,工作负荷可以是优化的sql语句或者sqlserver profiler的跟踪文件和数据表。我们可以在运行引擎优化顾问前运用sqlserver profiler记录一些事件,然后将跟踪结果存储为文件或者数据表,然后把这些提供给数据库引擎优化顾问,让它去分析。  提出合理的物理设计结构,物理设计结构包括数据库中的索引、索引视图、非聚集索引、聚集索引视图等等。对工作负荷进行分析后,数据库优化顾问会建议添加删除修改数据库的物理设计结构。推荐一组合理的物理结构以降低工作负荷的开销。从而提高数据库的性能 数据库性能优化的常见问题 如何发现问题,如何分析导致性能降低的原因仍然是数据库管理员要掌握的知识。 事务占用资源的时间过长,造成阻塞 许多用户同时访问数据库的时候会产生大量事务,许多用户同时竞争一个资源导致占用资源的时间过长,造成阻塞。从而降低了数据库执行效率。产生这样的现象的原因如下: 1、多表连接查询,查询期间占用多个表 2、事务需要占用太多资源,容易出现多个事务占用对方资源的状况。从而导致死锁 解决之道: 1、避免多表连接查询,联合过多的表会在查询中占用过多的资源。很容易因为别的事务占用资源而相互等待。 2、使用统一的SQL语句规范,特别是访问表的顺序要保持一致,这样可以避免互相占用资源而导致的死锁。 不合理的数据文件设置,影响事务处理的性能 当事务处理产生大量数据的时候,数据文件的大小如果设置不合理将导致数据文件的不断扩展,这也会影响到事务处理的性能,进而影响到整个数据库的性能。 1、频繁操作数据库,导致日志文件增长的过快,因为日志文件记录数据库的原始操作。所以它的增长速度比数据文件要快得多。当日志文件的增长大小设置不合理的时候会导致频繁地扩展文件。从而影响性能 2、查询操作比较频繁,系统数据Tempdb的大小设置不合理。 查询操作比较频繁的时候系统数据Tempdb增长得会比较快,因为查询所产生的临时数据都存放在这个数据库上。如果Tempdb过小当查询数据量较大的时候Tempdb会自动扩展,如果遇到频繁的查询会导致Tempdb不断扩展,从而影响系统性能。这种情况我尽可能地使查询的返回结果比较小 3、大量插入数据,导致数据文件增长过快。不要设置数据文件的自动收缩,它会在忙碌的系统上导致不必要的性能开销。所以如果没有特别需要不要设置数据库的自动收缩。最好采用手动收缩。 磁盘数据组织不合理,导致磁盘的访问次数过多 数据库的磁盘访问都是按照页来访问数据的,无论访问的数据再少都是以页为单位读取,1页为8K。所以如果将经常访问的数据放在一起,数据库读取尽量少的页面就能够完成读取操作。这样效率自然就提高了。也减少了磁盘头的来回移动。否则会多次读取硬盘页面导致访问的效率降低。 对于表A和表B、表C、表D,如果经常查询表A和表B中的数据,那么可以将他们放在同一个文件组M中;如果经常访问表C和表D中的数据可以将他们放在同一个文件组N中。这样读取效率就比较高,因为一次读取就可能包含了两个表中的数据,因此提高了查询效率。要解决“磁盘数据组织不合理,导致磁盘的访问次数过多”这个问题,我们可以将经常读写的数据放置在不同的磁盘上,也就是将经常在一起被多表连接查询的表放在同一个文件组上。这里强调:这里反复提到的“不同的磁盘”指的的是不同的磁盘,而不是同一个硬盘的不同分区。 批量导入数据的时候,要进行特殊设置 当用户需要大批量导入数据的时候会突然增加很多日志记录,并且如果数据表上有索引,数据表每增加一条记录就会在索引上增加一条数据从而降低插入的性能。解决方案: 1、大批量导入数据的时候设置数据库的恢复模式为“大容量日志恢复模式” 2、导入前禁用索引,导入完毕后重建索引。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值