数据库数据变大会导致查询慢

Why is my database so slow? This query used to be so much faster. Why does it take so long to rebuild my index? How come it was fine last month? Every day I am asked these types of questions by clients. Every day! A lot of database developers and application developers do not realize that indexes are ever changing entities within your database or rather they need to be monitored closely and managed periodically to remain efficient. I cannot even count the times someone tells me “but we have index’s on this or that column and it was fine last month” and so on. All while they fail to realize or even tell me that the database just took on, updated or deleted 1,000,000 records for example, which would definitely change the footprint of the data, making the index’s unsound or in need of help. Even adding 50 new users that use the data differently could require new indexes. That being said, I decided to automate a quick and easy data gathering and reporting job that helps to answer these questions. Most of the time query performance questions can be answered by determining the fragmentation levels of index’s, if there are missing index’s, duplicate index’s, unused index’s and what are the heavy hitters in regards to queries and are queries running in memory or to disk and how many executions. My favorite thing to do with SQL Server is automate, automate and automate the tasks that are asked of me over and over.

为什么我的数据库这么慢? 这个查询过去要快得多。 为什么重建索引需要这么长时间? 上个月还好吗? 客户每天都会问我这些类型的问题。 每天! 许多数据库开发人员和应用程序开发人员都没有意识到索引是数据库中不断变化的实体,或者需要对其进行密切监视和定期管理以保持效率。 我什至无法计算有人告诉我“但我们在该列上具有索引,上个月还不错”的次数等等。 他们全都无法意识到甚至告诉我,例如,数据库仅接受,更新或删除了1,000,000条记录,这肯定会改变数据的覆盖范围,从而使索引不可靠或需要帮助。 即使添加50个使用不同数据的新用户,也可能需要新索引。 话虽这么说,我决定自动化快速而轻松的数据收集和报告工作,以帮助回答这些问题。 在大多数情况下,查询性能问题可以通过确定索引的碎片级别来回答,如果缺少索引,重复索引,未使用的索引以及在查询方面的重击者是什么,以及在内存或磁盘中运行的查询以及如何运行许多处决。 我最喜欢的与SQL Server关联的事情是自动化,自动化和自动化一遍又一遍询问我的任务。

This simple job includes 9 tables used for collecting data, 7 reports, and one SQL agent job to tie it all together and do a cleanup step and finally kick off the tasks. Steps 1-5 below will show how to individually set up the job however, you can also just run “scripts 1-setup tables.sql” and “2-sgent job.sql” that are included here, however, make sure you update the variables with your information prior to running.

这个简单的工作包括9个用于收集数据的表,7个报告,以及一个SQL代理工作,将它们绑在一起并执行清理步骤,最后启动任务。 下面的步骤1-5将显示如何单独设置作业,但是,您也可以只运行此处包含的“ scripts 1-setup table.sql”和“ 2-sgent job.sql”,但是,请确保您进行更新在运行之前将变量与您的信息一起使用。

先决条件: ( Prerequisites: )

  1. I have created a small database on each server that I monitor called DBA_Monitoring, this is where I do most of my DBA tasks. This is optional of course; I like to keep my dba monitoring separate from other production databases. You can call yours whatever you like just be sure to change it in the scripts provided before you run them. 我在我监控的每个服务器上都创建了一个名为DBA_Monitoring的小型数据库,这是我执行大多数DBA任务的地方。 当然这是可选的。 我希望将dba监控与其他生产数据库分开。 您可以随心所欲地调用自己的脚本,只需在运行它们之前确保在提供的脚本中对其进行了更改。
  2. You must have dbMail enabled on your server that you will be monitoring and note your mail profile name as this will be used to send reports via email. 您必须在要监视的服务器上启用dbMail,并记下您的邮件配置文件名称,因为该名称将用于通过电子邮件发送报告。

创建收集包 ( Creating the Collection Package )

步骤1:创建表 ( Step 1: Create the tables )

I have created 9 tables in DBA_Monitoring to house each type of data collected in this job. 7 are for data collection and 2 are staging tables. These will need to be generated only once and will be truncated between data collection runs. Copy / Paste the scripts below and run them in your DBA_Monitoring database.

我在DBA_Monitoring中创建了9个表来容纳此作业中收集的每种数据类型。 7个用于数据收集,而2个是临时表。 这些将仅需要生成一次,并将在数据收集运行之间被截断。 复制/粘贴下面的脚本,然后在DBA_Monitoring数据库中运行它们。


--Create the tables
USE [DBA_Monitoring]
GO-- used to collect the first round of index read counts
CREATE TABLE [dbo].[IndexOverviewReadsWithCounts_stage]([ServerName] [nvarchar](128) NULL,[Database] [nvarchar](128) NULL,[Object] [nvarchar](128) NULL,[execution_count] [bigint] NOT NULL,[total_logical_reads] [bigint] NOT NULL,[total_physical_reads] [bigint] NOT NULL
) ON [PRIMARY]GO--used to collect the first round of index read counts and queries
CREATE TABLE [dbo].[IndexOverviewReadsWithQuery_stage]([ServerName] [nvarchar](128) NULL,[Database] [nvarchar](128) NULL,[Object] [nvarchar](128) NULL,[execution_count] [bigint] NOT NULL,[total_logical_reads] [bigint] NOT NULL,[total_physical_reads] [bigint] NOT NULL,[Statement] [nvarchar](max) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GO--used as final index reads with counts where database name is updated to the monitored database
CREATE TABLE [dbo].[IndexOverviewReadsWithCounts]([ServerName] [nvarchar](128) NULL,[Database] [nvarchar](128) NULL,[Object] [nvarchar](128) NULL,[execution_count] [bigint] NOT NULL,[total_logical_reads] [bigint] NOT NULL,[total_physical_reads] [bigint] NOT NULL
) ON [PRIMARY]
GO----used as final index reads with statements where database name is updated to the monitored database
CREATE TABLE [dbo].[IndexOverviewReadsWithQuery]([ServerName] [nvarchar](128) NULL,[Database] [nvarchar](128) NULL,[Object] [nvarchar](128) NULL,[execution_count] [bigint] NOT NULL,[total_logical_reads] [bigint] NOT NULL,[total_physical_reads] [bigint] NOT NULL,[Statement] [nvarchar](max) NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO--used to collect duplicate index
CREATE TABLE [dbo].[IndexOverview_DuplicateIndex]([ServerName] [nvarchar](128) NULL,[DBName] [varchar](100) NOT NULL,[TableName] [sysname] NOT NULL,[IndexName] [sysname] NULL,[OverLappingIndex] [sysname] NULL,[Col1] [nvarchar](128) NULL,[Col2] [nvarchar](128) NULL,[Col3] [nvarchar](128) NULL,[Col4] [nvarchar](128) NULL,[Col5] [nvarchar](128) NULL,[Col6] [nvarchar](128) NULL,[Col7] [nvarchar](128) NULL,[Col8] [nvarchar](128) NULL,[Col9] [nvarchar](128) NULL,[Col10] [nvarchar](128) NULL,[Col11] [nvarchar](128) NULL,[Col12] [nvarchar](128) NULL,[Col13] [nvarchar](128) NULL,[Col14] [nvarchar](128) NULL,[Col15] [nvarchar](128) NULL,[Col16] [nvarchar](128) NULL
) ON [PRIMARY]GO--used to collect fragmentation levels
CREATE TABLE [dbo].[IndexOverview_FragLevels]([ServerName] [nvarchar](128) NULL,[DBName] [varchar](100) NOT NULL,[Table] [sysname] NOT NULL,[Index] [sysname] NULL,[avg_fragmentation_in_percent] [float] NULL,[page_count] [bigint] NULL
) ON [PRIMARY]GO--used to collect the most expensive and longest running queries
CREATE TABLE [dbo].[IndexOverview_LongestQueries]([ServerName] [nvarchar](128) NULL,[DBName] [varchar](100) NOT NULL,[QueryName] [nvarchar](max) NULL,[ExecutionCount] [bigint] NOT NULL,[MaxElapsedTime] [bigint] NOT NULL,[AvgElapsedTime] [bigint] NOT NULL,[LogCreatedOn] [datetime] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]GO--used to collect missing index information
CREATE TABLE [dbo].[IndexOverview_MissingIndex]([ServerName] [nvarchar](128) NULL,[DBName] [varchar](100) NOT NULL,[DatabaseID] [smallint] NOT NULL,[Avg_Estimated_Impact] [float] NULL,[Last_User_Seek] [datetime] NULL,[TableName] [nvarchar](128) NULL,[Create_Statement] [nvarchar](4000) NULL
) ON [PRIMARY]GO--used to collect unused index information
CREATE TABLE [dbo].[IndexOverview_UnusedIndex]([ServerName] [nvarchar](128) NULL,[DBName] [varchar](100) NOT NULL,[ObjectName] [sysname] NOT NULL,[IndexName] [sysname] NULL,[IndexID] [int] NOT NULL,[UserSeek] [bigint] NOT NULL,[UserScans] [bigint] NOT NULL,[UserLookups] [bigint] NOT NULL,[UserUpdates] [bigint] NOT NULL,[TableRows] [bigint] NULL,[drop statement] [nvarchar](790) NULL
) ON [PRIMARY]
go

步骤2:收集资料 ( Step 2: Collect the data )

This step will collect data into the tables created in step 1 above. The queries here use data from SQL Server Dynamic Management Views (DMV), so data is only current between server restarts. Because of this, it is a good idea to know when the last server restart was. In my case, restarts for database servers is usually my responsibility or I am in touch with the server guys to verify the last server reboot. This ensures that I have enough data in the DMV’s that my reports are useful. Make sure you change the variables marked with <> throughout the scripts prior to running. In addition to this, some of the queries contain a threshold for the amount of rows to bring back, so do not forget to modify this to your needs as well. Copy/Paste the scripts below to collect data.

此步骤将数据收集到以上步骤1中创建的表中。 此处的查询使用来自SQL Server动态管理视图(DMV)的数据,因此数据仅在服务器重新启动之间是最新的。 因此,最好知道上一次服务器重新启动的时间。 就我而言,通常由我负责数据库服务器的重新启动,或者与服务器人员联系以验证上次服务器重新启动。 这样可以确保我在DMV中有足够的数据以使我的报告有用。 在运行之前,请确保在整个脚本中更改标有<>的变量。 除此之外,某些查询还包含要带回的行数的阈值,因此请不要忘记根据您的需要对其进行修改。 复制/粘贴以下脚本以收集数据。


--get the data
--need to do this entire script for each db to be monitored
USE <add your database name to monitor> -- change this to dbname to collect fromDeclare @DBName as varchar(100)
Set @DBName = '<add your database name to monitor>' --add db name here to be checked --get Index reads with statementINSERT INTO [DBA_Monitoring].[dbo].[IndexOverviewReadsWithQuery_Stage]([ServerName],[Database],[Object],[execution_count],[total_logical_reads],[total_physical_reads],[Statement])SELECT  @@ServerName, DB_NAME(st.dbid) [Database],OBJECT_NAME(st.objectid, st.dbid) [Object],qs.execution_count,qs.total_logical_reads,qs.total_physical_reads,st.text [Statement]
FROM    sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) stINSERT INTO [DBA_Monitoring].[dbo].[IndexOverviewReadsWithQuery]([ServerName],[Database],[Object],[execution_count],[total_logical_reads],[total_physical_reads],[Statement])SELECT [ServerName],[Database],[Object],[execution_count],[total_logical_reads],[total_physical_reads],[Statement]FROM [DBA_Monitoring].[dbo].[IndexOverviewReadsWithQuery_Stage]WHERE [Database] = @DBName--get Index reads with countsINSERT INTO [DBA_Monitoring].[dbo].[IndexOverviewReadsWithCounts_Stage]([ServerName],[Database],[Object],[execution_count],[total_logical_reads],[total_physical_reads])SELECT  @@ServerName, DB_NAME(database_id) [Database],OBJECT_NAME(object_id, database_id) [Object],execution_count,total_logical_reads,total_physical_reads
FROM    sys.dm_exec_procedure_stats;INSERT INTO [DBA_Monitoring].[dbo].[IndexOverviewReadsWithCounts]([ServerName],[Database],[Object],[execution_count],[total_logical_reads],[total_physical_reads])SELECT [ServerName],[Database],[Object],[execution_count],[total_logical_reads],[total_physical_reads]FROM [DBA_Monitoring].[dbo].[IndexOverviewReadsWithCounts_stage]WHERE [Database] = @DBName--get longest running queries
INSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_LongestQueries]([ServerName],[DBName],[QueryName],[ExecutionCount],[MaxElapsedTime],[AvgElapsedTime],[LogCreatedOn])
(SELECT DISTINCT TOP 25 @@SERVERNAME as ServerName, @DBName as DBName,
t.TEXT QueryName,
s.execution_count AS ExecutionCount,
s.max_elapsed_time AS MaxElapsedTime,
ISNULL(s.total_elapsed_time / s.execution_count, 0) AS AvgElapsedTime,
s.creation_time AS LogCreatedOn
FROM sys.dm_exec_query_stats s
CROSS APPLY sys.dm_exec_sql_text( s.sql_handle ) t)-- Unused Index Script
INSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_UnusedIndex]([ServerName],[DBName],[ObjectName],[IndexName],[IndexID],[UserSeek],[UserScans],[UserLookups],[UserUpdates],[TableRows],[drop statement])
(SELECT TOP 25 @@SERVERNAME as ServerName, @DBName as DBName, o.name AS ObjectName
, i.name AS IndexName
, i.index_id AS IndexID
, dm_ius.user_seeks AS UserSeek
, dm_ius.user_scans AS UserScans
, dm_ius.user_lookups AS UserLookups
, dm_ius.user_updates AS UserUpdates
, p.TableRows
, 'DROP INDEX ' + QUOTENAME(i.name)
+ ' ON ' + QUOTENAME(s.name) + '.' + QUOTENAME(OBJECT_NAME(dm_ius.object_id)) as 'drop statement'
FROM sys.dm_db_index_usage_stats dm_ius
INNER JOIN sys.indexes i ON i.index_id = dm_ius.index_id AND dm_ius.object_id = i.object_id
INNER JOIN sys.objects o on dm_ius.object_id = o.object_id
INNER JOIN sys.schemas s on o.schema_id = s.schema_id
INNER JOIN (SELECT SUM(p.rows) TableRows, p.index_id, p.object_id FROM sys.partitions p GROUP BY p.index_id, p.object_id) p ON p.index_id = dm_ius.index_id AND dm_ius.object_id = p.object_id
WHERE OBJECTPROPERTY(dm_ius.object_id,'IsUserTable') = 1
AND dm_ius.database_id = DB_ID()
AND i.type_desc = 'nonclustered'
AND i.is_primary_key = 0
AND i.is_unique_constraint = 0)-- Missing Index Script
INSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_MissingIndex]([ServerName],[DBName],[DatabaseID],[Avg_Estimated_Impact],[Last_User_Seek],[TableName],[Create_Statement])(SELECT TOP 25 @@SERVERNAME as ServerName, @DBName as DBName,
dm_mid.database_id AS DatabaseID,
dm_migs.avg_user_impact*(dm_migs.user_seeks+dm_migs.user_scans) Avg_Estimated_Impact,
dm_migs.last_user_seek AS Last_User_Seek,
object_name(dm_mid.object_id,dm_mid.database_id) AS [TableName],
'CREATE INDEX [IX_' + object_name(dm_mid.object_id,dm_mid.database_id) + '_'
+ REPLACE(REPLACE(REPLACE(ISNULL(dm_mid.equality_columns,''),', ','_'),'[',''),']','') +
CASEWHEN dm_mid.equality_columns IS NOT NULL AND dm_mid.inequality_columns IS NOT NULL THEN '_'ELSE ''
END
+ REPLACE(REPLACE(REPLACE(ISNULL(dm_mid.inequality_columns,''),', ','_'),'[',''),']','')
+ ']'
+ ' ON ' + dm_mid.statement
+ ' (' + ISNULL (dm_mid.equality_columns,'')
+ CASE WHEN dm_mid.equality_columns IS NOT NULL AND dm_mid.inequality_columns IS NOT NULL THEN ',' ELSE
'' END
+ ISNULL (dm_mid.inequality_columns, '')
+ ')'
+ ISNULL (' INCLUDE (' + dm_mid.included_columns + ')', '') AS Create_Statement
FROM sys.dm_db_missing_index_groups dm_mig
INNER JOIN sys.dm_db_missing_index_group_stats dm_migs
ON dm_migs.group_handle = dm_mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details dm_mid
ON dm_mig.index_handle = dm_mid.index_handle
WHERE dm_mid.database_ID = DB_ID())---fragmentation levels
INSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_FragLevels]([ServerName],[DBName],[Table],[Index],[avg_fragmentation_in_percent],[page_count])
(SELECT @@SERVERNAME as ServerName, @DBName as DBName,
dbtables.[name] as 'Table',
dbindexes.[name] as 'Index',
indexstats.avg_fragmentation_in_percent,
indexstats.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
AND indexstats.index_id = dbindexes.index_id
WHERE indexstats.database_id = DB_ID())GO
USE DBA_Monitoring  --update to db name to run against
go--Duplicate Index
WITH MyDuplicate AS (SELECT Obj.[name] AS TableName,Idx.[name] AS IndexName,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 1) AS Col1,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 2) AS Col2,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 3) AS Col3,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 4) AS Col4,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 5) AS Col5,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 6) AS Col6,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 7) AS Col7,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 8) AS Col8,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 9) AS Col9,INDEX_Col(Sch.[name] + '.' + Obj.[name], Idx.index_id, 10) AS Col10FROM sys.indexes Idx
INNER JOIN sys.objects Obj ON Idx.[object_id] = Obj.[object_id]
INNER JOIN sys.schemas Sch ON Sch.[schema_id] = Obj.[schema_id]
WHERE index_id > 0)
SELECT  MD1.TableName, MD1.IndexName, MD2.IndexName AS OverLappingIndex,MD1.Col1, MD1.Col2, MD1.Col3, MD1.Col4, MD1.Col5, MD1.Col6, MD1.Col7, MD1.Col8, MD1.Col9, MD1.Col10
INTO ##Duplicates
FROM MyDuplicate MD1
INNER JOIN MyDuplicate MD2 ON MD1.tablename = MD2.tablenameAND MD1.indexname <> MD2.indexnameAND MD1.Col1 = MD2.Col1AND (MD1.Col2 IS NULL OR MD2.Col2 IS NULL OR MD1.Col2 = MD2.Col2)AND (MD1.Col3 IS NULL OR MD2.Col3 IS NULL OR MD1.Col3 = MD2.Col3)AND (MD1.Col4 IS NULL OR MD2.Col4 IS NULL OR MD1.Col4 = MD2.Col4)AND (MD1.Col5 IS NULL OR MD2.Col5 IS NULL OR MD1.Col5 = MD2.Col5)AND (MD1.Col6 IS NULL OR MD2.Col6 IS NULL OR MD1.Col6 = MD2.Col6)AND (MD1.Col7 IS NULL OR MD2.Col7 IS NULL OR MD1.Col7 = MD2.Col7)AND (MD1.Col8 IS NULL OR MD2.Col8 IS NULL OR MD1.Col8 = MD2.Col8)AND (MD1.Col9 IS NULL OR MD2.Col9 IS NULL OR MD1.Col9 = MD2.Col9)AND (MD1.Col10 IS NULL OR MD2.Col10 IS NULL OR MD1.Col10 = MD2.Col10)Declare @DBName as varchar(100)
Set @DBName = '<add your database name to be monitored>' --add db name here to be checkedINSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_DuplicateIndex](ServerName,DBName,[TableName],[IndexName],[OverLappingIndex],[Col1],[Col2],[Col3],[Col4],[Col5],[Col6],[Col7],[Col8],[Col9],[Col10]
)(select @@ServerName, @DBName, [TableName],[IndexName],[OverLappingIndex],[Col1],[Col2],[Col3],[Col4],[Col5],[Col6],[Col7],[Col8],[Col9],[Col10]
from ##Duplicates)GO--get Index reads with countsINSERT INTO [DBA_Monitoring].[dbo].[IndexOverviewReadsWithCounts_Stage]([ServerName],[Database],[Object],[execution_count],[total_logical_reads],[total_physical_reads])      SELECT  @@ServerName, DB_NAME(database_id) [Database],OBJECT_NAME(object_id, database_id) [Object],execution_count,total_logical_reads,total_physical_readsFROM    sys.dm_exec_procedure_stats;
GO

步骤3:产生报告 ( Step 3: Generate the reports )

Each report is generated with HTML and sent via dbMail. These reports are called from within the SQL Agent Job one at a time after all of the data has been collected. Copy / Paste and run the scripts below to see the reports. Make sure to change the variables marked <> throughout.

每个报告都是使用HTML生成的,并通过dbMail发送。 收集完所有数据后,一次从SQL Agent Job中调用这些报告。 复制/粘贴并运行以下脚本以查看报告。 确保始终更改标记为<>的变量。

报告:未使用的索引 ( Report: Unused Index )

This report will provide unused indexes that are currently setup. DMV data is greatly important here as all indexes are not activated all the time. So be careful of your last server restart when reviewing this report. This report will also provide the appropriate drop statement that you can run to remove the unused index following analysis. I highly recommend scripting and saving the indexes prior to removing them in the event you need to add them back later.

该报告将提供当前设置的未使用索引。 DMV数据在这里非常重要,因为并非一直都激活所有索引。 因此,在查看此报告时,请注意您上次服务器重启。 该报告还将提供适当的drop语句,您可以运行该语句以在分析后删除未使用的索引。 我强烈建议编写脚本并保存索引,然后再删除它们,以防您以后需要将它们重新添加。


SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject='SQL Server - Index Overview_Unused Index ''<Add Server/Database Names>'''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_UnusedIndex
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N'<table border="1">' +
N'<tr>' +
N'<th>Server Name</th>' +
N'<th>DB Name</th>' +
N'<th>Object Name</th>' +
N'<th>Index Name</th>' +
N'<th>User Seek</th>' +
N'<th>User Scan</th>' +
N'<th>User Lookups</th>' +
N'<th>User Updates</th>' +
N'<th>Table Rows</th>' +
N'<th>Drop Statement</th>' +
N'</tr>' +
CAST ( ( SELECT td=[ServerName],''
,td=[DBname],''
,td=[ObjectName],''
,td=[IndexName],''
,td=[USERSeek],''
,td=[UserScans],''
,td=[UserLookups],''
,td=[UserUpdates],''
,td=[TableRows],''
,td=[drop statement],''
FROM DBA_Monitoring.dbo.IndexOverview_UnusedIndex
order by ServerName, DBName, IndexName
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = '<add your mail profile here>',
@recipients = '<add your email here>',
@subject = @Subject,
@body = @tableHTML,
@body_format = 'HTML' ;
END
Server Name DB Name Object Name Index Name User Seek User Scan User Lookups User Updates Table Rows Drop Statement
ServerName DatabaseName sampleObject IX_Sample 196 77 0 140 631 DROP INDEX [IX_Samples] ON [dbo].[databaseName]
服务器名称 数据库名称 对象名称 索引名称 用户寻求 用户扫描 用户查询 用户更新 表格行 放弃声明
服务器名称 数据库名称 sampleObject IX_ 样本 196 77 0 140 631 DROP INDEX [IX_ Samples ] ON [dbo]。[ databaseName ]

报告:缺少索引 ( Report: Missing Index )

This report will contain the missing indexes along with the create statement that could be used following analysis to generate the missing index. DMV data is greatly important here as all indexes are not activated all the time. So be careful of your last server restart when reviewing this report.

该报告将包含缺少的索引以及创建语句,可在分析之后使用该语句生成丢失的索引。 DMV数据在这里非常重要,因为并非一直都激活所有索引。 因此,在查看此报告时,请注意您上次服务器重启。


SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject='SQL Server - Index Overview_Missing Index ''<Add Server/Database Names>'''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_MissingIndex
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N'<table border="1">' +
N'<tr>' +
N'<th>Server Name</th>' +
N'<th>DB Name</th>' +
N'<th>Avg Estimated Impact (milliseconds)</th>' +
N'<th>Last User Seek</th>' +
N'<th>Table Name</th>' +
N'<th>Create Statement</th>' +
N'</tr>' +
CAST ( ( SELECT td=[ServerName],''
,td=[DBname],''
,td=Cast([Avg_Estimated_Impact] as varchar(25)),''
,td=[Last_User_Seek],''
,td=[TableName],''
,td=[Create_Statement],''
FROM DBA_Monitoring.dbo.IndexOverview_MissingIndex
order by ServerName, DBName, TableName
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = '<add your mail profile here>',
@recipients = '<add your email here>',
@subject = @Subject,
@body = @tableHTML,
@body_format = 'HTML' ;
END
Server Name DB Name Avg Estimated Impact (milliseconds) Last User Seek Table Name Create Statement
ServerName DatabaseName 299.64 2016-01-19T15:38:11.190 Some Table CREATE INDEX [IX_xxx_servername] ON [databaseName].[dbo].[xxx] (xx)
服务器名称 数据库名称 平均 估算影响(毫秒) 上次用户搜寻 表名 建立陈述
服务器名称 数据库名称 299.64 2016-01-19T15:38:11.190 一些表 创建索引[IX_ xxx _servername] ON [ databaseName ]。[dbo]。[ xxx ]( xx )

报告:重复索引 ( Report: Duplicate Index )

This report contains duplicate or overlapping indexes and a drop statement to clean them up following analysis. I highly recommend scripting and saving the indexes prior to removing them in the event you need to add them back later.

该报告包含重复或重叠的索引以及一个drop语句,以在分析后清理它们。 我强烈建议编写脚本并保存索引,然后再删除它们,以防您以后需要将它们重新添加。


SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject='SQL Server - Index Overview_Duplicate Index ''<Add Server/Database Names>'''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_DuplicateIndex
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N'<table border="1">' +
N'<tr>' +
N'<th>Server Name</th>' +
N'<th>DB Name</th>' +
N'<th>Table Name</th>' +
N'<th>Over Lapping Index</th>' +
N'<th>Col1</th>' +
N'<th>Col2</th>' +
N'<th>Col3</th>' +
N'<th>Col4</th>' +
N'<th>Col5</th>' +
N'<th>Col6</th>' +
N'<th>Col7</th>' +
N'<th>Col8</th>' +
N'<th>Col9</th>' +
N'<th>Col10</th>' +
N'</tr>' +
CAST ( ( SELECT td=[servername],''
,td=[dbname],''
,td=[OverlappingIndex],''
,td=[Col1],''
,td=[Col2],''
,td=[Col3],''
,td=[Col4],''
,td=[Col5],''
,td=[Col6],''
,td=[Col7],''
,td=[Col8],''
,td=[Col9],''
,td=[Col10],''FROM DBA_Monitoring.dbo.IndexOverview_DuplicateIndex
ORDER BYServerName, DBName, TableName,IndexName
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = '<add your mail profile here>',
@recipients = '<add your email here>',
@subject = @Subject,
@body = @tableHTML,
@body_format = 'HTML' ;
END

The example below has been truncated to only show up to 3 columns however the report will return up to 10 index columns.

下面的示例已被截断为仅显示最多3列,但是报告将最多返回10个索引列。

Server Name DB Name Table Name Overlapping Index Col1 Col2 Col3
ServerName DatabaseName Table name Index name Column name Column name Column name
服务器名称 数据库名称 表名 重叠指数 Col1 Col2 Col3
服务器名称 数据库名称 表名 索引名称 栏名 栏名 栏名

报告:最长的运行查询 ( Report: Longest Running Queries )

This report will contain the longest running/most expensive queries. This report is useful to see how many times a query is executed along with how long it takes to run.

该报告将包含运行时间最长/最昂贵的查询。 该报告对于查看查询执行了多少次以及运行需要多长时间很有用。


SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject='SQL Server - Index Overview_Longest Running Queries ''<Add Server/Database Names>'''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_LongestQueries
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N'<table border="1">' +
N'<tr>' +
N'<th>Server Name</th>' +
N'<th>DB Name</th>' +
N'<th>Query</th>' +
N'<th>Execution Count</th>' +
N'<th>Max Elasped Time (ms)</th>' +
N'<th>Avg Elsaped Time (ms)</th>' +
N'</tr>' +
CAST ( ( SELECT td=[ServerName],''
,td=[DBname],''
,td=[Queryname],''
,td=[ExecutionCount],''
,td=MaxElapsedTime,''
,td=AvgElapsedTime,''
FROM DBA_Monitoring.dbo.IndexOverview_LongestQueries
order by ServerName, DBName, QueryName, ExecutionCount
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = '<add your mail profile here>',
@recipients = '<add your email here>',
@subject = @Subject,
@body = @tableHTML,
@body_format = 'HTML' ;
END
Server Name DB Name Query Execution Count Max Elapsed Time (ms) Avg Elapsed Time (ms)
ServerName DatabaseName Query 16 200011 29751
服务器名称 数据库名称 询问 执行次数 最大 经过 时间 毫秒 平均 经过 时间( 毫秒
服务器名称 数据库名称 询问 16 200011 29751

报告:带语句的索引读取 ( Report: Index Reads with Statement )

This report will contain statistics against each object executed including the query that ran. In addition to this you will also see total logical reads and total physical reads. These are great for determining if queries are being run in memory or disk. These statistics are useful to determine if adding additional indexes could assist the query to run faster. Another benefit could be in determinig hardware updates such as memory or even server level settings such as the “maximum server memory” setting.

该报告将包含针对每个执行的对象的统计信息,包括运行的查询。 除此之外,您还将看到逻辑读取总数和物理读取总数。 这些对于确定查询是在内存还是磁盘中运行非常有用。 这些统计信息对于确定添加其他索引是否可以帮助查询更快地运行非常有用。 另一个好处是可以确定硬件更新(例如内存),甚至可以确定服务器级别的设置(例如“最大服务器内存”设置)。


SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject='SQL Server - Index Overview_Index Reads with Statements ''<Add Server/Database Names>'''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverviewReadsWithQuery
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N'<table border="1">' +
N'<tr>' +
N'<th>Server Name</th>' +
N'<th>DB Name</th>' +
N'<th>Object</th>' +
N'<th>Execution Count</th>' +
N'<th>Total Logical Reads</th>' +
N'<th>Total Physical Reads</th>' +
N'<th>Statement</th>' +
N'</tr>' +
CAST ( ( SELECT top 100 td=[ServerName],''
,td=[DataBase],''
,td=[Object],''
,td=[execution_count],''
,td=total_logical_reads,''
,td=total_physical_reads,''
,td=[Statement],''
FROM DBA_Monitoring.dbo.IndexOverviewReadsWithQuery
order by ServerName, [Database], [Object]
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = '<add your mail profile here>',
@recipients = '<add your email here>',
@subject = @Subject,
@body = @tableHTML,
@body_format = 'HTML' ;
END
Server Name DB Name Object Execution Count Total Logical Reads Total Physical Reads Statement
ServerName Database Name Object name 1 1 0 Query using the index here
服务器名称 数据库名称 目的 执行次数 逻辑读取总数 物理读取总数 声明
服务器名称 数据库名称 对象名称 1个 1个 0 在这里使用索引查询

报告:带有计数的索引读取 ( Report: Index Reads with Counts )

This report will contain counts for each database object executed against. This is similar to the Index Reads with Statement report however this report shows just the counts. This is great for just a quick peak into what is going on.

该报告将包含针对每个数据库对象执行的计数。 这类似于“带有语句的索引读取”报告,但是此报告仅显示计数。 这对于快速了解正在发生的事情非常有用。


SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject='SQL Server - Index Overview_Index Reads with Counts ''<Add Server/Database Names>'''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverviewReadsWithCounts
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N'<table border="1">' +
N'<tr>' +
N'<th>Server Name</th>' +
N'<th>DB Name</th>' +
N'<th>Object</th>' +
N'<th>Execution Count</th>' +
N'<th>Total Logical Reads</th>' +
N'<th>Total Physical Reads</th>' +
N'</tr>' +
CAST ( ( SELECT td=[ServerName],''
,td=[DataBase],''
,td=[Object],''
,td=[execution_count],''
,td=total_logical_reads,''
,td=total_physical_reads,''
FROM DBA_Monitoring.dbo.IndexOverviewReadsWithCounts
order by ServerName, [Database], [Object]
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = '<add your mail profile here>',
@recipients = '<add your email here>',
@subject = @Subject,
@body = @tableHTML,
@body_format = 'HTML' ;
END

This report will contain counts for each database object executed.

该报告将包含每个执行的数据库对象的计数。

Server Name DB Name Object Execution Count Total Logical Reads Total Physical Reads
ServerName DatabaseName Object Name 10 420 4
服务器名称 数据库名称 目的 执行次数 逻辑读取总数 物理读取总数
服务器名称 数据库名称 对象名称 10 420 4

报告:碎片级别 ( Report: Fragmentation Levels )

This report will contains index fragmentation % and page count for each index. When looking at the fragmentation %, a good rule of thumb for managing indexes is:

该报告将包含每个索引的索引碎片百分比和页数。 查看碎片%时,管理索引的一个好的经验法则是:

  • 0-5% fragmentation leave alone0-5%的碎片留下
  • 6-30% reorganize the index6-30%重组指数
  • 31% or higher rebuild the index31%或更高的重建指数

Also, do not forget to consider page count. Low page count and high fragmentation may not be an issue. For example 80% fragmentation and 5 pages should not cause alarm.

另外,不要忘记考虑页数。 低页数和高碎片可能不是问题。 例如,80%的碎片和5页不应引起警报。


SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject='SQL Server - Index Overview_Fragmentation Levels ''<Add Server/Database Names>'''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_FragLevels
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N'<table border="1">' +
N'<tr>' +
N'<th>Server Name</th>' +
N'<th>DB Name</th>' +
N'<th>Table</th>' +
N'<th>Index</th>' +
N'<th>Fragmentation %</th>' +
N'<th>Page Count</th>' +
N'</tr>' +
CAST ( ( SELECT td=[ServerName],''
,td=[DBname],''
,td=[Table],''
,td=IsNull([Index], 'HEAP - no clustered index'),''
,td=convert(varchar, round([avg_fragmentation_in_percent], 2)),''
,td=[page_count],''
FROM DBA_Monitoring.dbo.IndexOverview_FragLevels
order by ServerName, DBName, [Table], [Index]
FOR XML PATH('tr'), TYPE
) AS NVARCHAR(MAX) ) +
N'</table>' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = '<add your mail profile here>',
@recipients = '<add your email here>',
@subject = @Subject,
@body = @tableHTML,
@body_format = 'HTML' ;
END
Server Name DB Name Table Index Fragmentation % Page Count
ServerName DatabaseName Table Index 44 1254
服务器名称 数据库名称 指数 碎片% 页数
服务器名称 数据库名称 指数 44 1254

步骤4:清除资料 ( Step 4: Purge Data )

Following the data collection you will need to clean up the temp and staging tables before your next run. Paste this script to clean up the temp and staging tables. In the SQL Agent Job, I have this as the first step therefore the previous data is available between runs. If running it manually outside the SQL Agent job, you can just run this after you run reports. Copy / Paste the script below to purge the data prior to the next run.

在收集数据之后,您将需要在下一次运行之前清理临时表和登台表。 粘贴此脚本以清理临时表和登台表。 在SQL Agent Job中,我将其作为第一步,因此在运行之间可以使用先前的数据。 如果在SQL Agent作业之外手动运行它,则可以在运行报表后运行它。 复制/粘贴下面的脚本,以在下次运行之前清除数据。


--clean up
USE DBA_Monitoring
go
Truncate Table dbo.IndexOverviewReadsWithCounts
go
Truncate Table dbo.IndexOverviewReadsWithQuery
go
Truncate Table dbo.IndexOverviewReadsWithCounts_Stage
go
Truncate Table dbo.IndexOverviewReadsWithQuery_StageTruncate Table dbo.IndexOverview_DuplicateIndex
go
Truncate Table dbo.IndexOverview_FragLevels
go
Truncate Table dbo.IndexOverview_LongestQueries
go
Truncate Table dbo.IndexOverview_MissingIndex
go
Truncate Table dbo.IndexOverview_UnusedIndex
go
IF OBJECT_ID('tempdb..##Duplicates') IS NOT NULL
/*Then it exists*/DROP TABLE ##Duplicates

步骤5:SQL代理作业 ( Step 5: SQL Agent Job )

The SQL Agent Job ties the entire process together by calling steps 2-4 above. I usually call this job ad-hoc when someone complains about performance, however you could schedule it as well. Again, just a warning the data is only valid between server restarts so if you restarted the server a day or two ago your data will not be as rich as data collected after a month between the last server restart, so be wary of restarts. Below is what the SQL Agent Job looks like:

SQL代理作业通过调用上面的步骤2-4将整个过程联系在一起。 当有人抱怨绩效时,我通常称其为临时工,但是您也可以安排它。 再次提醒您,该数据仅在服务器重新启动之间才有效,因此,如果您在一两天前重新启动服务器,则数据将不如上次服务器重新启动之间一个月后收集的数据那样丰富,因此请小心重启。 下面是SQL Agent Job的外观:

Copy/Paste/Run the script below to create the above SQL Agent Job. Again please change the variables marked with <>

复制/粘贴/运行以下脚本以创建上述SQL代理作业。 再次请更改标有<>的变量


USE [msdb]
GO/****** Object:  Job [Index Overview]  ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object:  JobCategory [[Uncategorized (Local)]]]  ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollbackENDDECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'Index Overview', @enabled=1, @notify_level_eventlog=0, @notify_level_email=0, @notify_level_netsend=0, @notify_level_page=0, @delete_level=0, @description=N'Run this job (change run in db at script level) for a database that you want to get an overview of index''sThis includes the following data pulls and subsequent reports:
Duplicate Index
Missing Index
Unused Index
Longest Queries
Fragmentation Levels
Index Read Counts
Index Read Statements', @category_name=N'[Uncategorized (Local)]', @owner_login_name=N'SA', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [clean up]     ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'clean up', @step_id=1, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'--clean upUSE DBA_Monitoring
go
Truncate Table dbo.IndexOverviewReadsWithCounts
go
Truncate Table dbo.IndexOverviewReadsWithQuery
go
Truncate Table dbo.IndexOverviewReadsWithCounts_Stage
go
Truncate Table dbo.IndexOverviewReadsWithQuery_Stage
go
Truncate Table dbo.IndexOverview_DuplicateIndex
go
Truncate Table dbo.IndexOverview_FragLevels
go
Truncate Table dbo.IndexOverview_LongestQueries
go
Truncate Table dbo.IndexOverview_MissingIndex
go
Truncate Table dbo.IndexOverview_UnusedIndex
go
IF OBJECT_ID(''tempdb..##Duplicates'') IS NOT NULL
/*Then it exists*/DROP TABLE ##Duplicates
', @database_name=N'DBA_Monitoring', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=6
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [get the data]     ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'get the data', @step_id=2, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'--get the data
--need to do this entire script for each db
-- change DB name above to collect fromDeclare @DBName as varchar(100)
Set @DBName = ''<Add your db name to be monitored here>'' --add db name here to be checked --get longest running queries
INSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_LongestQueries]([ServerName],[DBName],[QueryName],[ExecutionCount],[MaxElapsedTime],[AvgElapsedTime],[LogCreatedOn])
(SELECT DISTINCT TOP 25 @@SERVERNAME as ServerName, @DBName as DBName,
t.TEXT QueryName,
s.execution_count AS ExecutionCount,
s.max_elapsed_time AS MaxElapsedTime,
ISNULL(s.total_elapsed_time / s.execution_count, 0) AS AvgElapsedTime,
s.creation_time AS LogCreatedOn
FROM sys.dm_exec_query_stats s
CROSS APPLY sys.dm_exec_sql_text( s.sql_handle ) t)-- Unused Index Script
INSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_UnusedIndex]([ServerName],[DBName],[ObjectName],[IndexName],[IndexID],[UserSeek],[UserScans],[UserLookups],[UserUpdates],[TableRows],[drop statement])
(SELECT TOP 25 @@SERVERNAME as ServerName, @DBName as DBName, o.name AS ObjectName
, i.name AS IndexName
, i.index_id AS IndexID
, dm_ius.user_seeks AS UserSeek
, dm_ius.user_scans AS UserScans
, dm_ius.user_lookups AS UserLookups
, dm_ius.user_updates AS UserUpdates
, p.TableRows
, ''DROP INDEX '' + QUOTENAME(i.name)
+ '' ON '' + QUOTENAME(s.name) + ''.'' + QUOTENAME(OBJECT_NAME(dm_ius.object_id)) as ''drop statement''
FROM sys.dm_db_index_usage_stats dm_ius
INNER JOIN sys.indexes i ON i.index_id = dm_ius.index_id AND dm_ius.object_id = i.object_id
INNER JOIN sys.objects o on dm_ius.object_id = o.object_id
INNER JOIN sys.schemas s on o.schema_id = s.schema_id
INNER JOIN (SELECT SUM(p.rows) TableRows, p.index_id, p.object_id FROM sys.partitions p GROUP BY p.index_id, p.object_id) p ON p.index_id = dm_ius.index_id AND dm_ius.object_id = p.object_idWHERE OBJECTPROPERTY(dm_ius.object_id,''IsUserTable'') = 1
AND dm_ius.database_id = DB_ID()
AND i.type_desc = ''nonclustered''
AND i.is_primary_key = 0
AND i.is_unique_constraint = 0)-- Missing Index Script
INSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_MissingIndex]([ServerName],[DBName],[DatabaseID],[Avg_Estimated_Impact],[Last_User_Seek],[TableName],[Create_Statement])(SELECT TOP 25 @@SERVERNAME as ServerName, @DBName as DBName,
dm_mid.database_id AS DatabaseID,
dm_migs.avg_user_impact*(dm_migs.user_seeks+dm_migs.user_scans) Avg_Estimated_Impact,
dm_migs.last_user_seek AS Last_User_Seek,
object_name(dm_mid.object_id,dm_mid.database_id) AS [TableName],
''CREATE INDEX [IX_'' + object_name(dm_mid.object_id,dm_mid.database_id) + ''_''
+ REPLACE(REPLACE(REPLACE(ISNULL(dm_mid.equality_columns,''''),'', '',''_''),''['',''''),'']'','''') +
CASEWHEN dm_mid.equality_columns IS NOT NULL AND dm_mid.inequality_columns IS NOT NULL THEN ''_''ELSE ''''
END
+ REPLACE(REPLACE(REPLACE(ISNULL(dm_mid.inequality_columns,''''),'', '',''_''),''['',''''),'']'','''')
+ '']''
+ '' ON '' + dm_mid.statement
+ '' ('' + ISNULL (dm_mid.equality_columns,'''')
+ CASE WHEN dm_mid.equality_columns IS NOT NULL AND dm_mid.inequality_columns IS NOT NULL THEN '','' ELSE
'''' END
+ ISNULL (dm_mid.inequality_columns, '''')
+ '')''
+ ISNULL ('' INCLUDE ('' + dm_mid.included_columns + '')'', '''') AS Create_Statement
FROM sys.dm_db_missing_index_groups dm_mig
INNER JOIN sys.dm_db_missing_index_group_stats dm_migs
ON dm_migs.group_handle = dm_mig.index_group_handle
INNER JOIN sys.dm_db_missing_index_details dm_mid
ON dm_mig.index_handle = dm_mid.index_handle
WHERE dm_mid.database_ID = DB_ID())---fragmentation levels
INSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_FragLevels]([ServerName],[DBName],[Table],[Index],[avg_fragmentation_in_percent],[page_count])
(SELECT @@SERVERNAME as ServerName, @DBName as DBName,
dbtables.[name] as ''Table'',
dbindexes.[name] as ''Index'',
indexstats.avg_fragmentation_in_percent,
indexstats.page_count
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
AND indexstats.index_id = dbindexes.index_id
WHERE indexstats.database_id = DB_ID())GO
--USE DBA_Monitoring  --update to db name to run against
--go--Duplicate Index
WITH MyDuplicate AS (SELECT Obj.[name] AS TableName,Idx.[name] AS IndexName,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 1) AS Col1,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 2) AS Col2,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 3) AS Col3,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 4) AS Col4,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 5) AS Col5,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 6) AS Col6,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 7) AS Col7,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 8) AS Col8,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 9) AS Col9,INDEX_Col(Sch.[name] + ''.'' + Obj.[name], Idx.index_id, 10) AS Col10,
FROM sys.indexes Idx
INNER JOIN sys.objects Obj ON Idx.[object_id] = Obj.[object_id]
INNER JOIN sys.schemas Sch ON Sch.[schema_id] = Obj.[schema_id]
WHERE index_id > 0)
SELECT  MD1.TableName, MD1.IndexName, MD2.IndexName AS OverLappingIndex,MD1.Col1, MD1.Col2, MD1.Col3, MD1.Col4, MD1.Col5, MD1.Col6, MD1.Col7, MD1.Col8, MD1.Col9, MD1.Col10
INTO ##Duplicates
FROM MyDuplicate MD1
INNER JOIN MyDuplicate MD2 ON MD1.tablename = MD2.tablenameAND MD1.indexname <> MD2.indexnameAND MD1.Col1 = MD2.Col1AND (MD1.Col2 IS NULL OR MD2.Col2 IS NULL OR MD1.Col2 = MD2.Col2)AND (MD1.Col3 IS NULL OR MD2.Col3 IS NULL OR MD1.Col3 = MD2.Col3)AND (MD1.Col4 IS NULL OR MD2.Col4 IS NULL OR MD1.Col4 = MD2.Col4)AND (MD1.Col5 IS NULL OR MD2.Col5 IS NULL OR MD1.Col5 = MD2.Col5)AND (MD1.Col6 IS NULL OR MD2.Col6 IS NULL OR MD1.Col6 = MD2.Col6)AND (MD1.Col7 IS NULL OR MD2.Col7 IS NULL OR MD1.Col7 = MD2.Col7)AND (MD1.Col8 IS NULL OR MD2.Col8 IS NULL OR MD1.Col8 = MD2.Col8)AND (MD1.Col9 IS NULL OR MD2.Col9 IS NULL OR MD1.Col9 = MD2.Col9)AND (MD1.Col10 IS NULL OR MD2.Col10 IS NULL OR MD1.Col10 = MD2.Col10)Declare @DBName as varchar(100)
Set @DBName = ''<add your database name here to monitor>'' --add db name here to be checkedINSERT INTO [DBA_Monitoring].[dbo].[IndexOverview_DuplicateIndex](ServerName,DBName,[TableName],[IndexName],[OverLappingIndex],[Col1],[Col2],[Col3],[Col4],[Col5],[Col6],[Col7],[Col8],[Col9],[Col10])(select @@ServerName, @DBName, [TableName],[IndexName],[OverLappingIndex],[Col1],[Col2],[Col3],[Col4],[Col5],[Col6],[Col7],[Col8],[Col9],[Col10]from ##Duplicates)', @database_name=N'<add your database name to be monitored here>', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=2
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [report - duplicate Index]      ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'report - duplicate Index', @step_id=3, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject=''SQL Server - Index Overview_Duplicate Index ''''Add Server Name''''''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_DuplicateIndex
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N''<table border="1">'' +
N''<tr>'' +
N''<th>Server Name</th>'' +
N''<th>DB Name</th>'' +
N''<th>Table Name</th>'' +
N''<th>Over Lapping Index</th>'' +
N''<th>Col1</th>'' +
N''<th>Col2</th>'' +
N''<th>Col3</th>'' +
N''<th>Col4</th>'' +
N''<th>Col5</th>'' +
N''<th>Col6</th>'' +
N''<th>Col7</th>'' +
N''<th>Col8</th>'' +
N''<th>Col9</th>'' +
N''<th>Col10</th>'' +
N''</tr>'' +
CAST ( ( SELECT td=[servername],''''
,td=[dbname],''''
,td=[OverlappingIndex],''''
,td=[Col1],''''
,td=[Col2],''''
,td=[Col3],''''
,td=[Col4],''''
,td=[Col5],''''
,td=[Col6],''''
,td=[Col7],''''
,td=[Col8],''''
,td=[Col9],''''
,td=[Col10],''''
FROM DBA_Monitoring.dbo.IndexOverview_DuplicateIndex
ORDER BYServerName, DBName, TableName,IndexName
FOR XML PATH(''tr''), TYPE
) AS NVARCHAR(MAX) ) +
N''</table>'' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = ''<add your mail profile>'',
@recipients = ''<add your email>'',
@subject = @Subject,
@body = @tableHTML,
@body_format = ''HTML'' ;END', @database_name=N'DBA_Monitoring', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [report - missing index]      ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'report - missing index', @step_id=4, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject=''SQL Server - Index Overview_Missing Index ''''Add Server Name''''''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_MissingIndex
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N''<table border="1">'' +
N''<tr>'' +
N''<th>Server Name</th>'' +
N''<th>DB Name</th>'' +
N''<th>Avg Estimated Impact (milliseconds)</th>'' +
N''<th>Last User Seek</th>'' +
N''<th>Table Name</th>'' +
N''<th>Create Statement</th>'' +
N''</tr>'' +
CAST ( ( SELECT td=[ServerName],''''
,td=[DBname],''''
,td=Cast([Avg_Estimated_Impact] as varchar(25)),''''
,td=[Last_User_Seek],''''
,td=[TableName],''''
,td=[Create_Statement],''''
FROM DBA_Monitoring.dbo.IndexOverview_MissingIndex
order by ServerName, DBName, TableName
FOR XML PATH(''tr''), TYPE
) AS NVARCHAR(MAX) ) +
N''</table>'' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = ''<add your mail profile>'',
@recipients = ''<add your email>'',
@subject = @Subject,
@body = @tableHTML,
@body_format = ''HTML'' ;END', @database_name=N'DBA_Monitoring', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=2
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [report- unused index]      ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'report- unused index', @step_id=5, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject=''SQL Server - Index Overview_Unused Index ''''Add Server Name''''''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_UnusedIndex
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N''<table border="1">'' +
N''<tr>'' +
N''<th>Server Name</th>'' +
N''<th>DB Name</th>'' +
N''<th>Object Name</th>'' +
N''<th>Index Name</th>'' +
N''<th>User Seek</th>'' +
N''<th>User Scan</th>'' +
N''<th>User Lookups</th>'' +
N''<th>User Updates</th>'' +
N''<th>Table Rows</th>'' +
N''<th>Drop Statement</th>'' +
N''</tr>'' +
CAST ( ( SELECT td=[ServerName],''''
,td=[DBname],''''
,td=[ObjectName],''''
,td=[IndexName],''''
,td=[USERSeek],''''
,td=[UserScans],''''
,td=[UserLookups],''''
,td=[UserUpdates],''''
,td=[TableRows],''''
,td=[drop statement],''''
FROM DBA_Monitoring.dbo.IndexOverview_UnusedIndex
order by ServerName, DBName, IndexName
FOR XML PATH(''tr''), TYPE
) AS NVARCHAR(MAX) ) +
N''</table>'' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = ''<add your mail profile>'',
@recipients = ''<add your email>'',
@subject = @Subject,
@body = @tableHTML,
@body_format = ''HTML'' ;END', @database_name=N'DBA_Monitoring', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=2
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [report  - longest running queries]      ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'report  - longest running queries', @step_id=6, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject=''SQL Server - Index Overview_Longest Running Queries ''''Add Server Name''''''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_LongestQueries
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N''<table border="1">'' +
N''<tr>'' +
N''<th>Server Name</th>'' +
N''<th>DB Name</th>'' +
N''<th>Query Name</th>'' +
N''<th>Execution Count</th>'' +
N''<th>Max Elasped Time (milliseconds)</th>'' +
N''<th>Avg Elsaped Time (milliseconds)</th>'' +
N''</tr>'' +
CAST ( ( SELECT td=[ServerName],''''
,td=[DBname],''''
,td=[Queryname],''''
,td=[ExecutionCount],''''
,td=MaxElapsedTime,''''
,td=AvgElapsedTime,''''
FROM DBA_Monitoring.dbo.IndexOverview_LongestQueries
order by ServerName, DBName, QueryName, ExecutionCount
FOR XML PATH(''tr''), TYPE
) AS NVARCHAR(MAX) ) +
N''</table>'' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = ''<add your mail profile>'',
@recipients = ''<add your email>'',
@subject = @Subject,
@body = @tableHTML,
@body_format = ''HTML'' ;END', @database_name=N'DBA_Monitoring', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [report - index read counts]      ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'report - index read counts', @step_id=7, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject=''SQL Server - Index Overview_Index Reads with Counts ''''<Add Server/Database Names>''''''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverviewReadsWithCounts
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N''<table border="1">'' +
N''<tr>'' +
N''<th>Server Name</th>'' +
N''<th>DB Name</th>'' +
N''<th>Object</th>'' +
N''<th>Execution Count</th>'' +
N''<th>Total Logical Reads</th>'' +
N''<th>Total Physical Reads</th>'' +
N''</tr>'' +
CAST ( ( SELECT td=[ServerName],''''
,td=[DataBase],''''
,td=[Object],''''
,td=[execution_count],''''
,td=total_logical_reads,''''
,td=total_physical_reads,''''
FROM DBA_Monitoring.dbo.IndexOverviewReadsWithCounts
order by ServerName, [Database], [Object]
FOR XML PATH(''tr''), TYPE
) AS NVARCHAR(MAX) ) +
N''</table>'' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = ''<add your mail profile here>'',
@recipients = ''<add your email here>'',
@subject = @Subject,
@body = @tableHTML,
@body_format = ''HTML'' ;END', @database_name=N'DBA_Monitoring', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=2
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [report - index read statements]      ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'report - index read statements', @step_id=8, @cmdexec_success_code=0, @on_success_action=3, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject=''SQL Server - Index Overview_Index Reads with Statements ''''<Add Server/Database Names>''''''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverviewReadsWithQuery
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N''<table border="1">'' +
N''<tr>'' +
N''<th>Server Name</th>'' +
N''<th>DB Name</th>'' +
N''<th>Object</th>'' +
N''<th>Execution Count</th>'' +
N''<th>Total Logical Reads</th>'' +
N''<th>Total Physical Reads</th>'' +
N''<th>Statement</th>'' +
N''</tr>'' +
CAST ( ( SELECT top 100 td=[ServerName],''''
,td=[DataBase],''''
,td=[Object],''''
,td=[execution_count],''''
,td=total_logical_reads,''''
,td=total_physical_reads,''''
,td=[Statement],''''
FROM DBA_Monitoring.dbo.IndexOverviewReadsWithQuery
order by ServerName, [Database], [Object]
FOR XML PATH(''tr''), TYPE
) AS NVARCHAR(MAX) ) +
N''</table>'' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = ''<add your mail profile here>'',
@recipients = ''<add your email here>'',
@subject = @Subject,
@body = @tableHTML,
@body_format = ''HTML'' ;END', @database_name=N'DBA_Monitoring', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=2
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [report - fragmentation levels]      ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'report - fragmentation levels', @step_id=9, @cmdexec_success_code=0, @on_success_action=1, @on_success_step_id=0, @on_fail_action=2, @on_fail_step_id=0, @retry_attempts=0, @retry_interval=0, @os_run_priority=0, @subsystem=N'TSQL', @command=N'SET nocount ON
--
DECLARE @Subject VARCHAR (100)
SET @Subject=''SQL Server - Index Overview_Fragmentation Levels ''''Add Server Name''''''DECLARE @Count AS INT
SELECT @Count=COUNT(*) FROM DBA_Monitoring.dbo.IndexOverview_FragLevels
PRINT @CountIF @Count > 0
BEGINDECLARE @tableHTML NVARCHAR(MAX) ;
SET @tableHTML =
N''<table border="1">'' +
N''<tr>'' +
N''<th>Server Name</th>'' +
N''<th>DB Name</th>'' +
N''<th>Table</th>'' +
N''<th>Index</th>'' +
N''<th>Fragmentation %</th>'' +
N''<th>Page Count</th>'' +
N''</tr>'' +
CAST ( ( SELECT td=[ServerName],''''
,td=[DBname],''''
,td=[Table],''''
,td=IsNull([Index], ''HEAP - no clustered index''),''''
,td=convert(varchar, round([avg_fragmentation_in_percent], 2)),''''
,td=[page_count],''''
FROM DBA_Monitoring.dbo.IndexOverview_FragLevels
order by ServerName, DBName, [Table], [Index]
FOR XML PATH(''tr''), TYPE
) AS NVARCHAR(MAX) ) +
N''</table>'' ;EXEC msdb.dbo.sp_send_dbmail
@profile_name = ''<add your mail profile>'',
@recipients = ''<add your email>'',
@subject = @Subject,
@body = @tableHTML,
@body_format = ''HTML'' ;END', @database_name=N'DBA_Monitoring', @output_file_name=N'<add your path>\IndexOverviewErrors.txt', @flags=2
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO

摘要: ( Summary: )

This is a step by step method to collect a high level overview of the condition of the Index’s and query executions for a specific database on your server. This information is taken directly from SQL Server making it readily available at any time as long as there has been a reasonable amount of time between server restarts. Data collected may help you answer the ever reoccurring questions about database performance and what you can do to improve it.

这是一种分步方法,用于收集有关索引状况的高级概述,并查询服务器上特定数据库的执行情况。 只要在服务器重新启动之间有一段合理的时间,此信息就直接从SQL Server获取,因此随时可以使用。 收集的数据可以帮助您回答有关数据库性能以及如何做的改进问题。

Included in this package are the following:

此程序包中包含以下内容:

  • Tables:表格:

    • IndexOverviewReadsWithCounts_stageIndexOverviewReadsWithCounts_stage
    • IndexOverviewReadsWithQuery_stageIndexOverviewReadsWithQuery_stage
    • IndexOverviewReadsWithCountsIndexOverviewReadsWithCounts
    • IndexOverviewReadsWithQueryIndexOverviewReadsWithQuery
    • IndexOverview_DuplicateIndexIndexOverview_DuplicateIndex
    • IndexOverview_FragLevelsIndexOverview_FragLevels
    • IndexOverview_LongestQueriesIndexOverview_Longest查询
    • IndexOverview_MissingIndexIndexOverview_MissingIndex
    • IndexOverview_UnusedIndexIndexOverview_UnusedIndex
  • Reports报告书
    • Duplicate Index重复索引
    • Missing Index缺少索引
    • Unused Index未使用索引
    • Longest Queries最长查询
    • Fragmentation Levels碎片级别
    • Index Read Counts索引读取计数
    • Index Read Statements索引读取语句
  • SQL Agent JobSQL代理作业
    • Index Overview索引总览

翻译自: https://www.sqlshack.com/what-is-causing-database-slowdowns/

数据库数据变大会导致查询慢

数据库数据变大会导致查询慢_是什么导致数据库变慢?相关推荐

  1. 数据库数据增删改查练习题(1)——学生选课数据库

    数据库数据增删改查练习题(1)--学生选课数据库 基本数据表 S(SNO,SNAME,AGE,SEX)学生 C(CNO,CNAME,TEACHER)课程 SC(SNO,CNO,GRADE)选课 练习题 ...

  2. access怎么查询工龄_计算机二级Access数据库查询的功能教程

    计算机二级Access数据库查询的功能教程 引导语:査询是Access数据库的重要对象,以下是百分网小编分享给大家的计算机二级Access数据库查询的功能教程,欢迎阅读! 查询的功能 使用Access ...

  3. 使用 DMV 进行监视_监视查询性能_针对 Azure SQL 数据库和 Azure SQL 托管实例进行手动性能优化

    本文适用:AZURE SQL数据库,AZURE SQL托管实例 SQL是系统和数据库交互的重要方式,日常工作中我们经常被性能糟糕的SQL所干扰.同样在AZURE数据库中,我们依旧面临相同的问题.缓慢或 ...

  4. mysql数据库时间突然是12小时制_为什么存入mysql数据库中的timestamp,晚了13或14个小时...

    # 为什么存入mysql数据库中的timestamp,晚了13个小时 ## 查看数据库时区 ``` show variables like '%time_zone%'; select @@global ...

  5. .net使用SqlBulkCopy类操作DataTable批量插入数据库数据,然后分页查询坑

    在使用SqlBulkCopy类操作DataTable批量插入数据,这种操作插入数据的效率很高,就会导致每一条数据在保存的时间基本一样,在我们分页查询添加的数据是,使用数据的添加时间来排序就会出现每页的 ...

  6. mysql管理数据 并上传至云端_怎样将MySQL数据库上传到服务器

    首先,需要将本地的数据库导出来,作为一个数据文件,以备稍后上传到服务器用,在本地登陆phpmyadmin控制面板: 登陆成功后,在左侧选择需要操作的数据库: 选择后,页面会自动刷新,然后再在右边点击[ ...

  7. mysql数据库简单查询试题_面试题: mysql数据库 已看1 简单的sql练习

    1.根据部门号从高到低,工资从低到高列出员工的信息 select * from employee order by dept_id desc,salary 2.union和union all的区别 用 ...

  8. mysql数据表字段繁体转简体_【WORD】阿拉伯数字变大写数字、简繁体转换等实用小技巧...

    WORD 01 阿拉伯数字秒变大写 有时候我们在做制订合同文档时,经常需要输入大写数字金额,Word中有什么快捷方法输入呢?一起来看一看! 技巧一:利用"编号" 输入阿拉伯数字,如 ...

  9. 数据库——数据操作——单表查询(9)

    单表查询 1.语法 SELECT 字段1,字段2... FROM 表名WHERE 条件GROUP BY fieldHAVING 筛选ORDER BY fieldLIMIT 限制条数 2.关键字的执行优 ...

最新文章

  1. JSP 学习笔记 3
  2. jsp,OGNL调用后台Action的某方法
  3. DS, DB, WEB模块的安装(环境搭建) 学习日志 2012年7月10日
  4. 谷歌 Daydream 实验室:VR中学习新技能是一种怎样的体验?
  5. 全阶滑模观测器程序_基于全阶状态滑模观测器的异步电机转子磁链观测_杨淑英...
  6. 「 每日一练,快乐水题 」1984. 学生分数的最小差值
  7. J2EE看tomcat运行参数和去掉工程名作为请求的根路径
  8. Netweaver和CloudFoundry的服务器日志
  9. 【VMCloud云平台】SCOM配置(额外篇)-应用可用性150点实时性测试
  10. 设备信息获取以及唯一标识资料
  11. 思科网院Packet Tracer实验(四)连接有线和无线 LAN
  12. jQuery制作带有微信二维码扫描的页面返回顶部代码
  13. dcs world f15c教学_开源声码器WORLD在语音合成中的应用
  14. 泰国之旅随感(70天)
  15. UNITY材质球合并
  16. [Solved] Pycharm 提示Unresolved reference
  17. 小甲鱼python 第003讲:小插曲之变量和字符串
  18. 特岗教师计算机专业面试题,2019特岗教师面试试题及参考答案
  19. 六大理由告诉你,为什么要用猪齿鱼工作日历
  20. LeetCode-House_Robber

热门文章

  1. java 获取当前方法的名称_Java中获取当前函数名
  2. 19n20c的参数_FQP19N20C电子元器件产品参数(BY 2021年)、Datasheet 文档资料和货源信息,FQP19N20C最新参考价格==www.ic37.com...
  3. sydney airport hotel recommendations
  4. JavaWeb——Servlet开发3
  5. Easyui Datagrid的Rownumber行号显示问题
  6. 还来一篇说下json_value 以及 json_query 的应用 (3)
  7. 8皇后问题--回溯法 (循环递归)
  8. LeetCode(1089)——复写零(JavaScript)
  9. Go语言---结构体
  10. 【Node】—nrm的简单使用