标签: execution-plan

SQL Server 2012 内连接估计行数问题

我有一个简单的连接,如下所示:

select * 
from fact_sales f
join dim_company d on f.company_SK = d.company_SK
Run Code Online (Sandbox Code Playgroud)

事实表包含略多于 5 亿条记录(带有 NC 列存储),查询将返回所有记录,但是,联接后的估计行数仅为 3 亿条。直到哈希连接,估计的行数是正确的,只有在连接之后才下降到 3 亿。这是查询的估计计划:

在此处输入图片说明

我已经更新了事实表(使用全扫描)和维度表中联接中使用的 SK 列的统计数据,这是每个表的直方图:

在此处输入图片说明

这个问题似乎只发生在数据库中的几个维度表上,加入其他维度表不会产生相同类型的基数估计问题 - 关于如何解决这个问题或进一步调查的任何建议?

如果我在查询中添加一个 where 子句,它会正确估计连接之前/之后的行数,例如

select * 
from fact_sales f
join dim_company d on f.company_SK = d.company_SK where company_SK = 1
Run Code Online (Sandbox Code Playgroud)

将估计来自连接的 467,583,000 行,这与直方图中的内容相匹配。

该问题似乎仅在查询中没有任何过滤器时才会发生。它在更大的查询中导致问题(排序溢出)。我已经将范围缩小到这个特定的连接。

我确实有一个 FK 约束,但它们WITH NOCHECK在事实表上已被关闭 ( )(我们被告知关闭它们以便 ETL 可以更快)。不幸的是,重新打开 FK 不是一种选择:(

更新:启用跟踪标志 2301 解决了这个问题:p

sql-server execution-plan sql-server-2012 cardinality-estimates

5
推荐指数
1
解决办法
624
查看次数

为什么我的查询一起运行比单独运行时花费的时间更长?

我有一系列遵循一般模式的更新语句:一次更新聚合来自另一个表(或有时是多个表)的值,下一次更新根据聚合值生成排名。对于总共 46 个更新语句,此过程重复 23 次。每个更新对独立运行需要 30-40 秒,但是当我通过 PgAdmin 将它们作为单个事务一起运行时,它需要一个多小时,而不是我期望的基于单个查询时间的约 15 分钟。(上次尝试时,我最终停止执行并单独运行它们。)

如果我通过 psql 在文件中运行相同的更新集,则该过程将在预期的 15 分钟时间内完成。

查询计划器是否有一些怪癖会根据在单个事务中运行的大量更新语句来更改执行计划?鉴于 psql 和 PgAdmin 之间的不同行为,我认为这与查询打包执行的方式有关,但我不太熟悉,无法了解其中的区别。

有没有办法编写我的代码,以便在通过 PgAdmin 作为单个事务运行时提高性能?

我在 Ubuntu 16.04 上使用 PostgreSQL 9.5。

以下是代码中的两个示例对联:

-- bike_driver_aggressive
UPDATE  generated.crash_aggregates
SET     bike_driver_aggressive = (
            SELECT  COUNT(*)
            FROM    crashes_bike2 c
            WHERE   c.int_id = crash_aggregates.int_id
            AND     c.aggressive_driverfault
        );
WITH ranks AS (
    SELECT  int_id,
            rank() OVER (ORDER BY bike_driver_aggressive DESC) AS rank
    FROM    crash_aggregates
)
UPDATE  generated.crash_aggregates
SET     bike_driver_aggressive_rank = ranks.rank
FROM    ranks
WHERE   crash_aggregates.int_id = ranks.int_id; …
Run Code Online (Sandbox Code Playgroud)

postgresql pgadmin execution-plan postgresql-9.5

5
推荐指数
1
解决办法
349
查看次数

Where 子句索引扫描 - 索引查找

我有下表:

CREATE TABLE Test
(
    Id int IDENTITY(1,1) NOT NULL,
    col1 varchar(37) NULL,
    testDate datetime NULL 
)

GO

insert Test    
select null
go 700000 

insert Test
select cast(NEWID() as varchar(37))
go 300000
Run Code Online (Sandbox Code Playgroud)

以及以下索引:

create clustered index CIX on Test(ID)
create nonclustered index IX_RegularIndex on Test(col1)
create nonclustered index IX_RegularDateIndex on Test(testDate)
Run Code Online (Sandbox Code Playgroud)

当我在我的桌子上查询时:

SET STATISTICS IO ON
select * from Test  where col1=NEWID()
select * from Test  where TestDate=GETDATE()
Run Code Online (Sandbox Code Playgroud)

首先是进行索引扫描,而第二个索引是搜索。我希望他们都必须进行索引查找。为什么先进行索引扫描?

在此处输入图片说明

index sql-server execution-plan

5
推荐指数
1
解决办法
807
查看次数

使用哈希匹配运算符实现的联合

我正在查看 TechNet 上列出的 SQL Server 物理运算符(不要判断,你知道你已经完成了)并读到哈希匹配物理运算符有时用于实现UNION逻辑运算符

我从未见过这样做过,并想了解更多。一个示例查询会很棒。什么时候使用它,什么时候它比替代品更好?(这些通常是相同的,但并非总是如此。)

sql-server optimization execution-plan database-internals union

5
推荐指数
3
解决办法
1532
查看次数

为什么这种隐式连接的规划方式与显式连接不同?

在这个答案中,我解释了 SQL-89 的隐式语法。
但是我在玩的时候注意到不同的查询计划:

EXPLAIN ANALYZE
  SELECT *
  FROM (values(1)) AS t(x), (values(2)) AS g(y);

                                     QUERY PLAN                                     
------------------------------------------------------------------------------------
 Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.002..0.002 rows=1 loops=1)
 Planning time: 0.052 ms
 Execution time: 0.020 ms
(3 rows)
Run Code Online (Sandbox Code Playgroud)

与此相反:

EXPLAIN ANALYZE
  SELECT *
  FROM (values(1)) AS t(x)                      
  CROSS JOIN (values(2)) AS g(y);
                                           QUERY PLAN                                           
------------------------------------------------------------------------------------------------
 Subquery Scan on g  (cost=0.00..0.02 rows=1 width=4) (actual time=0.004..0.005 rows=1 loops=1)
   ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.002..0.002 rows=1 loops=1)
 Planning time: 0.075 ms
 Execution time: 0.027 …
Run Code Online (Sandbox Code Playgroud)

postgresql performance join execution-plan postgresql-9.5 postgresql-performance

5
推荐指数
1
解决办法
1270
查看次数

Joining a function and a view

我有一个功能 get_sa001 and a view Axis_RefCustomer.

当我get_sa001在一段时间内单独执行我的函数时,比如说 2016 - 2017,执行时间约为 6 秒。

SELECT d."Selling_date",  d."Value_in_EUR", d."Value_in_currency", d."Site"
FROM report.get_sa001('2016-01-01'::date, '2017-03-31'::date, 32) AS d
Run Code Online (Sandbox Code Playgroud)

当我在视图上执行选择时Axis_RefCustomer,它运行大约 1 秒。

Select a."Selling_currency" FROM report."Axis_RefCustomer" AS a
Run Code Online (Sandbox Code Playgroud)

当我将它们连接在一起时,执行时间约为 39 秒!

SELECT d."Selling_date",
a."Selling_currency", 
d."Value_in_EUR", 
d."Value_in_currency", 
d."Site"
FROM report.get_sa001('2016-01-01'::date, '2017-03-31'::date, 32) AS d 
LEFT JOIN report."Axis_RefCustomer" 
AS a ON d."Site" = a."Site" 
AND d."Internal_reference" = a."Reference_internal" 
AND d."Customer_code" = a."Customer_code"
Run Code Online (Sandbox Code Playgroud)

Is there anyway to reduce the amount of time my query …

postgresql performance execution-plan plpgsql

5
推荐指数
1
解决办法
169
查看次数

CASE 语句和 SARGability - 特定用例

编辑:SQL Server - 我希望这是一个足够通用的问题,我不需要指定版本,但我使用的大多数实例都是 2012 或更高版本。

我不够好,无法模拟数据并实际测试它,所以我希望有人可以查看它并以简单的经验回答。

想象一下,您有一个州表,其中的一列包含美国州的缩写(并且已编入索引,就像一个很好的查找列)。在编写临时查询时,用户通常会点击此列进行过滤,但使用的条件表示数据库中未隐含的信息。

例如,如果他们想要获得“大状态”,他们可能会在他们的即席查询中包含一个过滤器,显示类似

...
where
  StateAbbreviation in ('AK', 'TX')
Run Code Online (Sandbox Code Playgroud)

又名可怕的“商业规则”

所以这个查询很好,它执行得很好,并且利用了索引。但是,伙计,每次我们需要查询“大国”时,写下来真是太糟糕了。我很想在它的定义中使用这个过滤器创建一个视图,以使其更容易使用。

这里的问题是,这些业务规则特定于一些支持业务线的即席查询,但实际上并没有普遍用途。因此,创建一个以这种方式过滤数据的视图将没有什么用处。

因此,我想编写一个计算条件结果的视图,而不是编写该条件在过滤器中的视图,例如

select 
  StateAbbreviation
  , IsBig = case when StateAbbreviation in ('AK' , 'TX') then 1 else 0 end
from tblStates
Run Code Online (Sandbox Code Playgroud)

现在,当他们想为大州写一个查询时,他们只需要包括

where IsBig = 1
Run Code Online (Sandbox Code Playgroud)

在查询中。

所以,我的问题很简单 - 如果使用该条件调用视图,是否可以使用 StateAbbreviation 上的索引?

我知道我可以在 CASE 语句中做各种可能会改变答案的事情,所以为了回答这个非常具体的问题,假设 case 语句看起来只会像那样。它不会使用多个字段,也不会聚合 - 只是简单的文字输入或输出计算,以更简单的方式向报告编写者公开复杂的过滤条件。

performance index sql-server t-sql execution-plan

5
推荐指数
3
解决办法
1138
查看次数

Seek 谓词中的标量运算符和 1 的行估计

我试图了解我在查询计划中看到的一些相当大且不守规矩的行为。特别是,我正在查看在其谓词中包含标量操作的聚集索引查找操作。我怀疑标量操作只是其中一个表的别名(如Seek Predicate中的标量运算符中所述),因为两列的类型相同,并且此操作馈入并行嵌套循环(左外连接)运算符。

不过,我的问题更多是关于 1 的行估计,而不是更接近实际行数(约 670 万)的数字。标量操作是否会扼杀优化器正确估计行的能力?我假设是这样,也假设这会损害我的查询执行计划的最佳状态,但我不确定。有人可以证实或反驳我的怀疑以及为什么吗?

这是有问题的操作:

在此处输入图片说明

版本:SQL Server 2012 企业版

sql-server execution-plan sql-server-2012

5
推荐指数
1
解决办法
712
查看次数

如何在从查询缓存或查询存储中提取的执行计划中包含“实际行”计数?

显然,在调整时看到实际的执行计划很重要,通常我通过启用查询计划输出SET STATISTICS XML ON并运行任何需要一些 TLC 的查询,但是我如何才能看到计划的历史运行或进程的实际记录计数我不能轻松手动运行(或在测试环境中模拟)?

当我通过显示sys.dm_exec_query_plansys.dm_exec_text_query_plan仅显示估计的行数从查询缓存中提取此信息时。使用查询存储 DMV 时存在相同的行为,sys.query_store_plan. 由于所有这些 DMV 都在提取已使用的实际计划,我希望在计划的图形表示中看到实际的行执行计数,但它们并不存在。

sys.dm_exec_query_statsDMV返回的信息只是在某种程度上有用,因为它返回语句的总计数,但计划中的详细操作员计数似乎隐藏在历史计划中。在 2014 年,我们sys.dm_exec_query_profiles使用了DMV,这有助于当前正在执行的计划,但这在查看历史执行时也无济于事。

这些信息是否存储在其他地方?我是否应该将估计行数视为实际计数(我对此表示怀疑,但因为我在问......)?是否有请求此功能的连接项目我可以投票?

sql-server execution-plan dmv

5
推荐指数
1
解决办法
416
查看次数

即使为查询授予了大量内存,哈希连接也会溢出到磁盘

我们正在运行SQL Server 2014 Enterprise Sp2使用1.5TB的内存和64 cores17 GB这个单线程查询的内存接近,使用的最大内存是2.2gb,即使散列连接有足够的可用内存,它似乎没有使用它并溢出到磁盘。知道为什么吗?先感谢您。

SQLPerformance 中发布的相同问题。查询计划和图像张贴在那里

完整计划

查询授权

哈希溢出

我想了解内存分数。它显示哈希连接具有 52.48% 的内存授权(总计 17GB+),接近 9GB。但是该计划使用的最大内存要少得多,即 2.2+GB,并且 Hash join 是此查询中唯一的溢出。我对内存分数有什么遗漏,它们不准确吗?

sql-server memory execution-plan

5
推荐指数
2
解决办法
1564
查看次数