标签: optimization

为什么在这些计划中对唯一索引进行(相同)1000 次搜索的估计成本不同?

在下面的查询中,估计两个执行计划对唯一索引执行 1,000 次搜索。

查找是由对同一源表的有序扫描驱动的,因此看起来最终应该以相同的顺序查找相同的值。

两个嵌套循环都有 <NestedLoops Optimized="false" WithOrderedPrefetch="true">

任何人都知道为什么这个任务在第一个计划中的成本为 0.172434,而在第二个计划中为 3.01702?

(问题的原因是第一个查询被建议作为优化,因为计划成本明显低得多。它实际上在我看来好像它做了更多的工作,但我只是试图解释这种差异.. .)

设置

CREATE TABLE dbo.Target(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL);

CREATE TABLE dbo.Staging(KeyCol int PRIMARY KEY, OtherCol char(32) NOT NULL); 

INSERT INTO dbo.Target
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1,  
     master..spt_values v2;

INSERT INTO dbo.Staging
SELECT TOP (1000) ROW_NUMBER() OVER (ORDER BY @@SPID), LEFT(NEWID(),32)
FROM master..spt_values v1;
Run Code Online (Sandbox Code Playgroud)

查询 1 “粘贴计划”链接

WITH T
     AS (SELECT *
         FROM   Target AS T
         WHERE  T.KeyCol …
Run Code Online (Sandbox Code Playgroud)

sql-server optimization sql-server-2014

28
推荐指数
3
解决办法
628
查看次数

为什么我的 SELECT DISTINCT TOP N 查询会扫描整个表?

我遇到了一些SELECT DISTINCT TOP N查询,这些查询似乎被 SQL Server 查询优化器优化得很差。让我们从一个简单的例子开始:具有两个交替值的百万行表。我将使用GetNums函数来生成数据:

DROP TABLE IF EXISTS X_2_DISTINCT_VALUES;

CREATE TABLE X_2_DISTINCT_VALUES (PK INT IDENTITY (1, 1), VAL INT NOT NULL);

INSERT INTO X_2_DISTINCT_VALUES WITH (TABLOCK) (VAL)
SELECT N % 2
FROM dbo.GetNums(1000000);

UPDATE STATISTICS X_2_DISTINCT_VALUES WITH FULLSCAN;
Run Code Online (Sandbox Code Playgroud)

对于以下查询:

SELECT DISTINCT TOP 2 VAL
FROM X_2_DISTINCT_VALUES
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

SQL Server 可以通过扫描表的第一个数据页找到两个不同的值,但它会扫描所有数据。为什么 SQL Server 不进行扫描,直到找到所需数量的不同值?

对于这个问题,请使用以下测试数据,其中包含 1000 万行,并在块中生成 10 个不同的值:

DROP TABLE IF EXISTS X_10_DISTINCT_HEAP;

CREATE TABLE X_10_DISTINCT_HEAP (VAL VARCHAR(10) NOT …
Run Code Online (Sandbox Code Playgroud)

sql-server optimization sql-server-2016

28
推荐指数
3
解决办法
6494
查看次数

SQL Server 将 A &lt;&gt; B 拆分为 A &lt; B OR A &gt; B,如果 B 是不确定的,则会产生奇怪的结果

我们在 SQL Server 中遇到了一个有趣的问题。考虑以下重现示例:

CREATE TABLE #test (s_guid uniqueidentifier PRIMARY KEY);
INSERT INTO #test (s_guid) VALUES ('7E28EFF8-A80A-45E4-BFE0-C13989D69618');

SELECT s_guid FROM #test
WHERE s_guid = '7E28EFF8-A80A-45E4-BFE0-C13989D69618'
  AND s_guid <> NEWID();

DROP TABLE #test;
Run Code Online (Sandbox Code Playgroud)

小提琴

请暂时忘记s_guid <> NEWID()条件似乎完全无用 - 这只是一个最小的重现示例。由于NEWID()匹配某个给定常量的概率极小,因此每次都应评估为 TRUE。

但事实并非如此。运行此查询通常会返回 1 行,但有时(非常频繁,超过 10 次中的 1 次)返回 0 行。我已经在我的系统上使用 SQL Server 2008 复制了它,您可以使用上面链接的小提琴 (SQL Server 2014) 在线复制它。

查看执行计划显示查询分析器显然将条件拆分为s_guid < NEWID() OR s_guid > NEWID()

查询计划截图

...这完全解释了为什么它有时会失败(如果第一个生成的 ID 小于给定的 ID,而第二个生成的 ID 大于给定的 ID)。 …

sql-server optimization

26
推荐指数
3
解决办法
1383
查看次数

EXPLAIN ANALYZE 不显示 plpgsql 函数内查询的详细信息

我在 PostgreSQL 9.3 中使用了一个 PL/pgSQL 函数,里面有几个复杂的查询:

create function f1()
  returns integer as
$$
declare

event tablename%ROWTYPE;
....
....

begin

FOR event IN
   SELECT * FROM tablename WHERE condition
LOOP
   EXECUTE 'SELECT f2(event.columnname)' INTO dummy_return;
END LOOP;

...

INSERT INTO ... FROM a LEFT JOIN b ... LEFT JOIN c WHERE ...

UPDATE T SET cl1 = M.cl1 FROM M WHERE M.pkcols = T.pkcols;

...

end
$$ language plpgsql;
Run Code Online (Sandbox Code Playgroud)

如果我跑了EXPLAIN ANALYZE f1(),我只会得到总时间,但没有细节。有没有办法可以获得函数中所有查询的详细结果?

如果函数中的查询不应该被 Postgres 优化,我也会要求解释。

postgresql optimization plpgsql functions explain

25
推荐指数
1
解决办法
2万
查看次数

如何加快选择不同的?

我在一些时间序列数据上有一个简单的选择:

SELECT DISTINCT user_id
FROM events
WHERE project_id = 6
AND time > '2015-01-11 8:00:00'
AND time < '2015-02-10 8:00:00';
Run Code Online (Sandbox Code Playgroud)

它需要112秒。这是查询计划:

http://explain.depesz.com/s/NTyA

我的应用程序必须执行许多不同的操作并像这样计数。有没有更快的方法来获取这种数据?

postgresql performance optimization postgresql-9.3 amazon-rds query-performance

25
推荐指数
2
解决办法
4万
查看次数

如何在大表上使用 LEFT JOIN 优化非常慢的 SELECT

我在谷歌上搜索、自我教育和寻找解决方案几个小时,但没有运气。我在这里发现了一些类似的问题,但不是这种情况。

我的表:

  • 人(约 1000 万行)
  • 属性(位置,年龄,...)
  • 人员和属性之间的链接 (M:M)(约 40M 行)

完全转储 ~280MB

情况: 我尝试person_id从某些位置 ( location.attribute_value BETWEEN 3000 AND 7000) 中选择所有人员 ID ( ) ,具有某种性别 ( gender.attribute_value = 1),出生于某些年份 ( bornyear.attribute_value BETWEEN 1980 AND 2000) 并且具有某种眼睛颜色 ( eyecolor.attribute_value IN (2,3))。

这是我的查询女巫花了3~4 分钟。我想优化:

SELECT person_id
FROM person
    LEFT JOIN attribute location ON location.attribute_type_id = 1 AND location.person_id = person.person_id
    LEFT JOIN attribute gender ON gender.attribute_type_id = 2 AND gender.person_id = person.person_id
    LEFT JOIN …
Run Code Online (Sandbox Code Playgroud)

mysql performance optimization eav query-performance

25
推荐指数
2
解决办法
10万
查看次数

SQL:2008 标准中是否指定了 CTE(带查询)的优化栅栏行为?如果有,在哪里?

我看到频繁引用WITH查询(公共表表达式,或 CTE)充当优化栅栏,服务器不允许将过滤器下推到 CTE 查询中,将公共表达式从 CTE 中拉出等。它经常被声称成为 SQL 标准要求的行为。

CTE绝对PostgreSQL 中的优化栅栏……但这是标准要求的,还是实际上只是实现细节?

例如,这些邮件列表帖子声称或建议它是标准的:

评论中提到它之后,我被问到它的指定位置 - 在查看了 SQL:2008 的唯一草案后,我可以访问我并没有太多运气找到它。

我还没有深入研究标准,所以我希望有人提出建议:标准实际上是否需要PostgreSQL中CTE的优化围栏?如果是这样,它在哪里指定?还是 Pg 邮件列表上的陈述有误?

另见todo list上的线程CTE优化围栏?.

postgresql optimization sql-standard

24
推荐指数
1
解决办法
2883
查看次数

LIKE 运算符的基数估计(局部变量)

我的印象是,当LIKE在所有针对未知场景的优化中使用运算符时,旧版和新版 CE 都使用 9% 的估计值(假设相关统计数据可用并且查询优化器不必求助于选择性猜测)。

当对信用数据库执行以下查询时,我在不同的 CE 下得到不同的估计。在新的 CE 下,我收到了我期望的 900 行的估计值,在旧版 CE 下,我收到了 241.416 的估计值,但我无法弄清楚这个估计值是如何得出的。有没有人能够发光?

-- New CE (Estimate = 900)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName;

-- Forcing Legacy CE (Estimate = 241.416)
DECLARE @LastName VARCHAR(15) = 'BA%'
SELECT * FROM [Credit].[dbo].[member]
WHERE [lastname] LIKE @LastName
OPTION (
QUERYTRACEON 9481,
QUERYTRACEON 9292,
QUERYTRACEON 9204,
QUERYTRACEON 3604
);
Run Code Online (Sandbox Code Playgroud)

在我的场景中,我已经将信用数据库设置为兼容性级别 120,因此为什么在第二个查询中我使用跟踪标志来强制使用旧版 CE 并提供有关查询优化器使用/考虑的统计信息的信息。我可以看到正在使用有关“姓氏”的列统计信息,但我仍然无法弄清楚 241.416 的估计值是如何得出的。

除了这篇 Itzik Ben-Gan 文章之外,我在网上找不到任何其他 …

sql-server optimization statistics sql-server-2014 cardinality-estimates

24
推荐指数
2
解决办法
2258
查看次数

为什么这个查询不使用索引假脱机?

我问这个问题是为了更好地了解优化器的行为并了解索引假脱机的限制。假设我将 1 到 10000 之间的整数放入堆中:

CREATE TABLE X_10000 (ID INT NOT NULL);
truncate table X_10000;

INSERT INTO X_10000 WITH (TABLOCK)
SELECT TOP 10000 ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;
Run Code Online (Sandbox Code Playgroud)

并强制嵌套循环连接MAXDOP 1

SELECT *
FROM X_10000 a
INNER JOIN X_10000 b ON a.ID = b.ID
OPTION (LOOP JOIN, MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

这是对 SQL Server 采取的相当不友好的操作。当两个表都没有任何相关索引时,嵌套循环连接通常不是一个好的选择。这是计划:

错误查询

在我的机器上查询需要 13 秒,从 table spool 中提取了 100000000 行。但是,我不明白为什么查询必须很慢。查询优化器能够通过索引假脱机动态创建索引。这个查询似乎是索引假脱机的完美候选者。

以下查询返回与第一个相同的结果,具有索引假脱机,并且在不到一秒的时间内完成:

SELECT *
FROM X_10000 a
CROSS APPLY …
Run Code Online (Sandbox Code Playgroud)

sql-server optimization index-spool sql-server-2016

23
推荐指数
1
解决办法
2582
查看次数

OPTIMIZE_FOR_SEQUENTIAL_KEY 的实施和禁忌症

SQL Server 2019 CTP3.1引入了解决最后一页插入争用的优化。这采用名为的索引选项的形式OPTIMIZE_FOR_SEQUENTIAL_KEY

有人认为这可能是Bw-TreeBz-Tree的改编。然而,这些依赖于可变大小的页面,而当前的存储引擎需要固定大小的页面。

优化是如何实现的?这种优化如何改变当前的 B 树算法?在什么情况下我会选择部署此选项?

研究

反向密钥方法的专利。

我使用 DBCC PAGE 快速浏览了一下,比较了 2017 年与 2019 年和 2019 年在 int IDENTITY 列的唯一聚集索引上使用和不使用 OPTIMIZE_FOR_SEQUENTIAL_KEY 的情况。没有什么可以明显地解释这种新行为。这让我觉得它是一个算法的东西,而不是一个结构的东西,这是有道理的。

来自 MS的博客文章

此功能似乎以检测和避免车队为中心。

sql-server optimization sql-server-2019

23
推荐指数
1
解决办法
640
查看次数