AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 151995
Accepted
James Lupolt
James Lupolt
Asked: 2016-10-12 09:10:46 +0800 CST2016-10-12 09:10:46 +0800 CST 2016-10-12 09:10:46 +0800 CST

对 SQL Server 2016 中包含 SUBSTRING() 的谓词的估计值的更改?

  • 772

是否有关于 SQL Server 2016 中关于如何为包含 SUBSTRING() 或其他字符串函数的谓词估计基数的更改的任何文档或研究?

我问的原因是我正在查看一个查询,该查询在兼容模式 130 下性能下降,原因与与包含对 SUBSTRING() 调用的 WHERE 子句匹配的行数估计值的变化有关。我通过查询重写纠正了这个问题,但我想知道是否有人知道有关 SQL Server 2016 中此区域更改的任何文档。

演示代码如下。在此测试用例中,估计值非常接近,但准确性因数据而异。

在测试用例中,在兼容级别 120 中,SQL Server 似乎使用直方图进行估计,而在兼容级别 130 中,SQL Server 似乎假设固定的 10% 的表匹配。

CREATE DATABASE MyStringTestDB;
GO
USE MyStringTestDB;
GO
DROP TABLE IF EXISTS dbo.StringTest;
CREATE TABLE dbo.StringTest ( [TheString] varchar(15) );
GO
INSERT INTO dbo.StringTest
VALUES
( 'Y5_CLV' );
INSERT INTO dbo.StringTest
VALUES
( 'Y5_EG3' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_NE' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_PQT' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_T2V' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_TT4' );
INSERT INTO dbo.StringTest
VALUES
( 'ZY_ZKK' );
INSERT INTO dbo.StringTest
VALUES
( 'ZZ_LW6' );
INSERT INTO dbo.StringTest
VALUES
( 'ZZ_QO3' );
INSERT INTO dbo.StringTest
VALUES
( 'ZZ_TZ7' );
INSERT INTO dbo.StringTest
VALUES
( 'ZZ_UZZ' );

CREATE CLUSTERED INDEX IX_Clustered ON dbo.StringTest (TheString);

/* 
Uses fixed % for estimate; 1.1 rows estimated in this case.
    Plan for computation:
        CSelCalcFixedFilter (0.1) <----
            Selectivity: 0.1
*/
ALTER DATABASE MyStringTestDB SET compatibility_level = 130;
GO
SELECT * 
FROM dbo.StringTest 
WHERE SUBSTRING(TheString, 1, CHARINDEX('_',TheString) - 1) = 'ZZ'
OPTION (QUERYTRACEON 2363, QUERYTRACEON 3604);

/* 
Uses histogram to get estimate of 1
 CSelCalcPointPredsFreqBased <----
      Distinct value calculation:
          CDVCPlanLeaf
              0 Multi-Column Stats, 1 Single-Column Stats, 0 Guesses
      Individual selectivity calculations:
          (none)
    Loaded histogram for column QCOL: [DBA].[dbo].[StringTest].TheString from stats with id 1
*/
ALTER DATABASE MyStringTestDB SET compatibility_level = 120;
GO
SELECT * 
FROM dbo.StringTest 
WHERE SUBSTRING(TheString, 1, CHARINDEX('_',TheString) - 1) = 'ZZ'
OPTION (QUERYTRACEON 2363, QUERYTRACEON 3604);

/*
-- Simpler rewrite; works fine in both compat levels and gets better estimate.
SELECT * 
FROM dbo.StringTest 
WHERE TheString LIKE 'ZZ[_]%'
OPTION (QUERYTRACEON 2363, QUERYTRACEON 3604);
*/
sql-server optimization
  • 1 1 个回答
  • 387 Views

1 个回答

  • Voted
  1. Best Answer
    Martin Smith
    2016-10-23T11:56:02+08:002016-10-23T11:56:02+08:00

    我不知道有任何文件。我确实对此进行了调查并进行了一些观察,但是对于评论来说太长了。

    10% 的估计并不总是退化。以下面的例子为例。

    TRUNCATE TABLE dbo.StringTest
    
    INSERT INTO dbo.StringTest
    SELECT TOP (1000000) 'ZZ_' + LEFT(NEWID(), 12)
    FROM   master..spt_values v1,
           master..spt_values v2;
    

    和WHERE你问题中的条款。

    WHERE SUBSTRING(TheString, 1, CHARINDEX('_',TheString) - 1) = 'ZZ'
    

    该表包含一百万行。它们都匹配谓词。在兼容级别 130 下,10% 的猜测会产生 100,000 的估计值。低于 120 的估计行数为 1.03913。

    120 行为使用直方图,但仅用于获取不同行的数量。在我的例子中,密度向量显示 1.039131E-06 并将其乘以表基数以获得估计的行数。所有的值实际上都是不同的,但都与谓词相匹配。

    跟踪query_optimizer_estimate_cardinality扩展事件表明在 130 以下有两个不同的<StatsCollection Name="CStCollFilter"事件。第一个估计有 100,000 个。第二个加载直方图并使用 CSelCalcPointPredsFreqBased/DistinctCountCalculator 获得 1.04 估计值。第二个结果似乎未使用。

    您观察到的行为在 130 中并未始终如一地应用。我补充说,我ORDER BY TheString希望这对 130 估计器来说是一个明显的胜利,因为 120 为一行的内存授予而苦苦挣扎,但这个微小的变化足以将估计的行数降低到130 的情况下也是 1.03913。

    添加OPTION (QUERYRULEOFF SelectToFilter)会将进入排序的估计值恢复为 100,000,但内存授予不会增加,并且排序后的估计值仍然基于表的不同值。

    在此处输入图像描述

    类似地调整并行度的成本阈值,以便查询获得并行计划足以在 130 的情况下恢复到较低的估计。添加QUERYTRACEON 8757也会导致较低的估计。看起来 10% 的估计只保留用于琐碎的计划。

    您建议的重写

    WHERE TheString LIKE 'ZZ[_]%'
    

    显示出比两者都高得多的估计。这个的输出是

      CSelCalcTrieBased
    
          Column: QCOL: [MyStringTestDB].[dbo].[StringTest].TheString
    

    表明它使用了try。有关此的更多信息,请参见此处上方的字符串摘要统计部分。

    但是,它与您的原始查询不同。由于_现在假定第一个实例始终是第三个字符,而不是动态找到的。

    如果此假设被硬编码到您的原始查询中

     WHERE SUBSTRING(TheString, 1, 3) = 'ZZ_'
    

    估计方法更改为CSelCalcHistogramComparison(INTERVAL),估计的行变得准确。

    它能够将其转换为一个范围

    WHERE TheString >=  'ZZ_' AND TheString < ???
    

    并使用直方图估计值在该范围内的行数。

    然而,这仅适用于基数估计。LIKE更可取,因为它可以在运行时使用范围搜索。SUBSTRING(TheString, 1, 3)或者LEFT(TheString, 3)不能。

    • 8

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve