如何在不访问showplan的情况下优化SQL查询?
我正在编写复杂的即席查询,以从客户端的SQL Server提取数据。有些查询需要半小时或更长时间才能运行,我需要它们在5分钟或更短时间内执行。不幸的是,我没有权限查看showplan或任何如何在不访问showplan的情况下优化SQL查询?,sql,sql-server,tsql,query-optimization,Sql,Sql Server,Tsql,Query Optimization,我正在编写复杂的即席查询,以从客户端的SQL Server提取数据。有些查询需要半小时或更长时间才能运行,我需要它们在5分钟或更短时间内执行。不幸的是,我没有权限查看showplan或任何sys.dm视图来帮助我优化它们 我确实可以访问所有的信息\u模式和sys目录视图,因此我知道存在哪些索引,并且我还可以使用统计时间和IO来帮助我衡量更改的有效性 既然我没有比较展示计划的能力,我如何才能最好地使用这些工具来引导我的直觉,以尽量减少耗时的尝试和错误?或者是否有人有任何创新的解决方案,在过去为他们
sys.dm
视图来帮助我优化它们
我确实可以访问所有的信息\u模式
和sys
目录视图,因此我知道存在哪些索引,并且我还可以使用统计时间
和IO
来帮助我衡量更改的有效性
既然我没有比较展示计划的能力,我如何才能最好地使用这些工具来引导我的直觉,以尽量减少耗时的尝试和错误?或者是否有人有任何创新的解决方案,在过去为他们工作过
编辑:我只有db_DataReader权限——我不能创建新对象或索引,但我可以创建临时表并为它们编制索引 以下是我将探讨的策略。根据经验法则,绝大多数查询优化都是通过使用覆盖索引来避免表扫描和哈希匹配联接来实现的 查看需要包含在查询中的每个表,以及需要在
JOIN ON
子句或WHERE
子句中使用的列。如果表有一个包含所有这些列的索引,那么您可以继续在查询中使用该表。您甚至可以使用查询提示来强制查询使用覆盖索引,但不需要它
如果表中没有这样的索引,那么您需要用使用现有索引可以获得的最小数据量填充临时表
举一个超级简单的例子,假设有一个包含10列和100万行的表,它在Column1
上只有一个索引。在查询中,您需要加入列2
上的表,并在结果集中包含列3
(仅限)
但除此之外,对于最终的结果集,您只对Column1
值在1-100之间的数据感兴趣
我将创建一个只有列2
和列3
的临时表,在列2
上有一个聚集索引,并用插入填充它。选择,使用列1
上的WHERE
子句过滤器从原始表获取数据,以仅获取我需要的行
通过这种方式,您可以在尽可能最小的表上建立索引,这有望使您在使用扫描原始表的查询时获得显著的性能提升。研究SQL Server的内部结构并实践查询计划预测的艺术
通过对已知数据(基数、密度、分布等)编写查询来练习。确保查询足够复杂,这是一个挑战。然后看看你是否能在脑海中描绘出这个计划。这和实际情况相比吗。当您开始计算SQL何时会选择循环v散列v合并联接类型和其他类似的操作(如排序、top等)时。。。然后你开始对它有感觉了
关于内部文档,从来没有一本书比这本更好。因为Ken已经不在了:(,我不确定现在最好的书是什么。我通过感觉学习如何做到这一点的方法是研究内部
您可以下载免费版本的SQL Server(许多版本),以便查看查询计划:。请将其用于实践
实践中有许多记录良好的样本数据库:
在使用图形查询计划之前,我们使用时间、io统计数据和showplan
实用的方法是:不要在客户端生产数据库中运行复杂的查询,而是从中提取必要的数据。然后将其余的查询运行到您自己的实例或测试环境。您是否需要访问sys.dm uu视图
才能访问SSMS中的执行计划
?如果是客户端的SQL Server,则需要您是否有权在其上创建索引?它们在SQL Server中是独立的安全文件。我曾希望使用sys.dm_uu视图可以让我查看计划缓存或当前执行查询的计划。当然,您的客户端可以授予您访问权限或运行查询并为您获取执行计划的副本。老实说,如果您没有允许建立索引,我不知道看到执行计划会有多大帮助。请看下面我的答案,如果这不起作用,也许会坚持得到执行计划。OP知道这些。问题是,“我如何最好地使用这些工具来引导我的直觉,以尽量减少耗时的尝试和错误?”因此,他们可能在寻求某种方法。Op明确提到,他不能使用showplan
查询提示来添加您的答案。这就是他们在解决实际问题时所应考虑的问题。
SET STATISTICS IO ON
SET STATISTICS TIME ON
go
SET SHOWPLAN_ALL ON
go
SELECT o.*, od.*
FROM [dbo].[Orders] o
INNER JOIN [dbo].[Order Details] od
ON o.OrderID = od.OrderID
WHERE od.OrderID = 10248
go
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
StmtText StmtId NodeId Parent PhysicalOp LogicalOp Argument DefinedValues EstimateRows EstimateIO EstimateCPU AvgRowSize TotalSubtreeCost OutputList Warnings Type Parallel EstimateExecutions
------------------------- ----------- ----------- ----------- ------------------------------ ------------------------------ -------- ------------- ------------- ------------- ------------- ----------- ---------------- ---------- -------- ---------------------------------------------------------------- -------- ------------------
SET STATISTICS IO ON 1 1 0 NULL NULL 1 NULL NULL NULL NULL NULL NULL NULL NULL SET STATS 0 NULL
SET STATISTICS TIME ON 2 2 0 NULL NULL 2 NULL NULL NULL NULL NULL NULL NULL NULL SET STATS 0 NULL
(2 row(s) affected)
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
StmtText StmtId NodeId Parent PhysicalOp LogicalOp Argument DefinedValues EstimateRows EstimateIO EstimateCPU AvgRowSize TotalSubtreeCost OutputList Warnings Type Parallel EstimateExecutions
---------------------- ----------- ----------- ----------- ------------------------------ ------------------------------ -------- ------------- ------------- ------------- ------------- ----------- ---------------- ---------- -------- ---------------------------------------------------------------- -------- ------------------
SET SHOWPLAN_ALL ON 1 1 0 NULL NULL 1 NULL NULL NULL NULL NULL NULL NULL NULL SET ON/OFF 0 NULL
(1 row(s) affected)
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
StmtText StmtId NodeId Parent PhysicalOp LogicalOp Argument DefinedValues EstimateRows EstimateIO EstimateCPU AvgRowSize TotalSubtreeCost OutputList Warnings Type Parallel EstimateExecutions
----------------------------------------------------------------------------------------------------------------------------------------------------- ----------- ----------- ----------- ------------------------------ ------------------------------ --------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ------------- ------------- ------------- ----------- ---------------- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------- ---------------------------------------------------------------- -------- ------------------
SELECT o.*, od.*
FROM [dbo].[Orders] o
INNER JOIN [dbo].[Order Details] od
ON o.OrderID = od.OrderID
WHERE od.OrderID = 10248 1 1 0 NULL NULL 1 NULL 3 NULL NULL NULL 0.00658094 NULL NULL SELECT 0 NULL
|--Nested Loops(Inner Join) 1 2 1 Nested Loops Inner Join NULL NULL 3 0 1.254E-05 254 0.00658094 [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o].[RequiredDate], [o].[ShippedDate], [o].[ShipVia], [o].[Freight], [o].[ShipName], [o].[ShipAddress], [o].[ShipCity], [o].[ShipRegion], [o].[ShipPostalCode], [o].[ShipCountry], [od].[Ord NULL PLAN_ROW 0 1
|--Clustered Index Seek(OBJECT:([Northwind].[dbo].[Orders].[PK_Orders] AS [o]), SEEK:([o].[OrderID]=(10248)) ORDERED FORWARD) 1 3 2 Clustered Index Seek Clustered Index Seek OBJECT:([Northwind].[dbo].[Orders].[PK_Orders] AS [o]), SEEK:([o].[OrderID]=(10248)) ORDERED FORWARD [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o].[RequiredDate], [o].[ShippedDate], [o].[ShipVia], [o].[Freight], [o].[ShipName], [o].[ShipAddress], [o].[ShipCity], [o].[ShipRegion], [o].[ShipPostalCode], [o].[ShipCountry] 1 0.003125 0.0001581 231 0.0032831 [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o].[RequiredDate], [o].[ShippedDate], [o].[ShipVia], [o].[Freight], [o].[ShipName], [o].[ShipAddress], [o].[ShipCity], [o].[ShipRegion], [o].[ShipPostalCode], [o].[ShipCountry] NULL PLAN_ROW 0 1
|--Clustered Index Seek(OBJECT:([Northwind].[dbo].[Order Details].[PK_Order_Details] AS [od]), SEEK:([od].[OrderID]=(10248)) ORDERED FORWARD) 1 4 2 Clustered Index Seek Clustered Index Seek OBJECT:([Northwind].[dbo].[Order Details].[PK_Order_Details] AS [od]), SEEK:([od].[OrderID]=(10248)) ORDERED FORWARD [od].[OrderID], [od].[ProductID], [od].[UnitPrice], [od].[Quantity], [od].[Discount] 3 0.003125 0.0001603 29 0.0032853 [od].[OrderID], [od].[ProductID], [od].[UnitPrice], [od].[Quantity], [od].[Discount] NULL PLAN_ROW 0 1
(4 row(s) affected)