小编Geo*_*son的帖子

全文索引维护指南

维护全文索引应考虑哪些准则?

我应该重建还是重组全文目录(请参阅BOL)?什么是合理的维护节奏?可以使用哪些启发式方法(类似于 10% 和 30% 碎片阈值)来确定何时需要维护?

(下面的所有内容只是详细说明该问题并显示我到目前为止所想的内容的额外信息。)



额外信息:我的初步研究

有很多关于 b 树索引维护的资源(例如,这个问题Ola Hallengren 的脚本以及来自其他站点的大量关于该主题的博客文章)。但是,我发现这些资源都没有提供用于维护全文索引的建议或脚本。

Microsoft 文档提到对基表的 b 树索引进行碎片整理然后在全文目录上执行重组可能会提高性能,但它没有涉及任何更具体的建议。

我也发现了这个问题,但它主要关注更改跟踪(如何将底层表的数据更新传播到全文索引中),而不是可以最大化索引效率的定期维护的类型。

额外信息:基本性能测试

SQL Fiddle包含的代码可用于创建带有AUTO更改跟踪的全文索引,并在修改表中的数据时检查索引的大小和查询性能。当我在生产数据的副本上运行脚本的逻辑(而不是小提琴中的人工制造数据)时,以下是我在每个数据修改步骤后看到的结果的摘要:

在此处输入图片说明

尽管此脚本中的更新语句相当人为,但这些数据似乎表明定期维护可以获得很多好处。

额外信息:初步想法

我正在考虑创建一个每晚或每周的任务。似乎此任务可以执行 REBUILD 或 REORGANIZE。

因为全文索引可能非常大(数千万或数亿行),所以我希望能够检测目录中的索引何时足够碎片化,从而需要进行 REBUILD/REORGANIZE。我有点不清楚什么启发式可能对此有意义。

sql-server full-text-search index-maintenance

31
推荐指数
1
解决办法
9005
查看次数

SQL Server 2014:对不一致的自连接基数估计有什么解释?

考虑 SQL Server 2014 中的以下查询计划:

在此处输入图片说明

在查询计划中,自联接ar.fId = ar.fId产生 1 行的估计值。然而,这是一个逻辑上不一致的估计:ar20,608行和只有一个不同的值fId(准确地反映在统计数据中)。因此,此连接会生成行 ( ~424MMrows)的完整叉积,从而导致查询运行数小时。

我很难理解为什么 SQL Server 会得出一个很容易证明与统计数据不一致的估计值。有任何想法吗?

初步调查和其他细节

根据 Paul在此处回答,用于估计连接基数的 SQL 2012 和 SQL 2014 启发式方法似乎都应该可以轻松处理需要比较两个相同直方图的情况。

我从跟踪标志 2363 的输出开始,但不太容易理解。请问下面的片段意味着SQL Server在比较直方图fIdbId以估计选择性的只加入使用fId?如果是这样,那显然是不正确的。还是我误读了跟踪标志输出?

Plan for computation:
  CSelCalcExpressionComparedToExpression( QCOL: [ar].fId x_cmpEq QCOL: [ar].fId )
Loaded histogram for column QCOL: [ar].bId from stats with id 3
Loaded histogram for column QCOL: [ar].fId from stats with id 1 …
Run Code Online (Sandbox Code Playgroud)

performance sql-server execution-plan sql-server-2014 cardinality-estimates query-performance

28
推荐指数
1
解决办法
759
查看次数

为什么 LEN() 函数严重低估了 SQL Server 2014 中的基数?

我有一个带有字符串列的表和一个检查具有特定长度的行的谓词。在 SQL Server 2014 中,无论我检查的长度如何,我都会看到估计为 1 行。这产生了非常糟糕的计划,因为实际上有数千甚至数百万行,而 SQL Server 选择将此表放在嵌套循环的外侧。

对于 SQL Server 2014 的基数估计为 1.0003 而 SQL Server 2012 估计为 31,622 行,是否有解释?有没有好的解决方法?

以下是该问题的简短再现:

-- Create a table with 1MM rows of dummy data
CREATE TABLE #customers (cust_nbr VARCHAR(10) NOT NULL)
GO

INSERT INTO #customers WITH (TABLOCK) (cust_nbr)
    SELECT TOP 1000000 
        CONVERT(VARCHAR(10),
        ROW_NUMBER() OVER (ORDER BY (SELECT NULL))) AS cust_nbr
    FROM master..spt_values v1
    CROSS JOIN master..spt_values v2
GO

-- Looking for string of a certain length.
-- While both CEs …
Run Code Online (Sandbox Code Playgroud)

sql-server varchar functions sql-server-2014 cardinality-estimates

26
推荐指数
2
解决办法
1486
查看次数

SQL Server 不会优化两个等效分区表上的并行合并连接

提前为非常详细的问题道歉。我已经包含了生成完整数据集以重现问题的查询,并且我正在 32 核机器上运行 SQL Server 2012。但是,我认为这不是 SQL Server 2012 特有的,并且我已将这个特定示例的 MAXDOP 强制为 10。

我有两个使用相同分区方案进行分区的表。在用于分区的列上将它们连接在一起时,我注意到 SQL Server 无法像预期的那样优化并行合并连接,因此选择使用 HASH JOIN 代替。在这种特殊情况下,我能够通过基于分区函数将查询拆分为 10 个不相交的范围并在 SSMS 中同时运行这些查询中的每一个来手动模拟更优化的并行 MERGE JOIN。使用 WAITFOR 精确地同时运行它们,结果是所有查询在原始并行 HASH JOIN 所用总时间的 40% 左右完成。

在等效分区表的情况下,有什么方法可以让 SQL Server 自行进行这种优化?我知道 SQL Server 通常可能会产生大量开销,以便并行执行 MERGE JOIN,但在这种情况下,似乎有一种非常自然的分片方法,开销最小。也许这只是优化器还不够聪明以识别的特殊情况?

以下是设置简化数据集以重现此问题的 SQL:

/* Create the first test data table */
CREATE TABLE test_transaction_properties 
    ( transactionID INT NOT NULL IDENTITY(1,1)
    , prop1 INT NULL
    , prop2 FLOAT NULL
    )

/* Populate table with pseudo-random data (the specific data doesn't …
Run Code Online (Sandbox Code Playgroud)

join sql-server partitioning

22
推荐指数
1
解决办法
6320
查看次数

为什么 Concatenation 运算符估计的行数少于其输入?

在下面的查询计划片段中,很明显Concatenation运算符的行估计应该是~4.3 billion rows,或者它的两个输入的行估计的总和。

但是,~238 million rows会产生的估计值,从而导致将数百 GB 数据溢出到 tempdb的次优Sort/Stream Aggregate策略。在这种情况下,逻辑上一致的估计会产生Hash Aggregate,消除溢出并显着提高查询性能。

这是 SQL Server 2014 中的错误吗?是否存在任何有效情况下低于输入值的估计是合理的?可能有哪些解决方法?

在此处输入图片说明

这是完整的查询计划(匿名)。我没有系统管理员访问此服务器的权限以提供来自QUERYTRACEON 2363或类似跟踪标志的输出,但如果它们有帮助,我可以从管理员那里获取这些输出。

数据库的兼容性级别为 120,因此使用新的 SQL Server 2014 Cardinality Estimator。

每次加载数据时都会手动更新统计信息。鉴于数据量,我们目前使用默认采样率。较高的采样率(或FULLSCAN)可能会产生影响。

performance sql-server concat sql-server-2014 cardinality-estimates query-performance

20
推荐指数
2
解决办法
783
查看次数

使用子查询对大表进行缓慢更新

由于SourceTable具有 >15MM 记录和Bad_Phrase>3K 记录,以下查询需要将近 10 个小时才能在 SQL Server 2005 SP4 上运行。

UPDATE [SourceTable] 
SET 
    Bad_Count=
             (
               SELECT 
                  COUNT(*) 
               FROM Bad_Phrase 
               WHERE 
                  [SourceTable].Name like '%'+Bad_Phrase.PHRASE+'%'
             )
Run Code Online (Sandbox Code Playgroud)

在英语中,这个查询计数Bad_Phrase列出不同的短语是一个子领域的数量NameSourceTable,然后把该结果在现场Bad_Count

我想要一些关于如何让这个查询运行得更快的建议。

sql-server-2005 sql-server subquery update

16
推荐指数
2
解决办法
1519
查看次数

SQL Server 2014 COUNT(DISTINCT x) 忽略列 x 的统计密度向量

对于一个COUNT(DISTINCT)具有约 10 亿个不同值的查询计划,我得到了一个散列聚合估计只有约 300 万行的查询计划。

为什么会这样?SQL Server 2012 产生了很好的估计,所以这是我应该在 Connect 上报告的 SQL Server 2014 中的错误吗?

查询和差估计

-- Actual rows: 1,011,719,166
-- SQL 2012 estimated rows: 1,079,130,000 (106% of actual)
-- SQL 2014 estimated rows: 2,980,240 (0.29% of actual)
SELECT COUNT(DISTINCT factCol5)
FROM BigFactTable
OPTION (RECOMPILE, QUERYTRACEON 9481) -- Include this line to use SQL 2012 CE

-- Stats for the factCol5 column show that there are ~1 billion distinct values
-- This is a good estimate, and it …
Run Code Online (Sandbox Code Playgroud)

sql-server sql-server-2014 cardinality-estimates

16
推荐指数
1
解决办法
630
查看次数

可以对 SQL Server 系统表进行碎片整理吗?

我们有几个数据库,其中创建和删除了大量表。据我们所知,SQL Server 不对系统基表进行任何内部维护,这意味着它们会随着时间的推移变得非常碎片化并变得臃肿。这会给缓冲池带来不必要的压力,也会对计算数据库中所有表的大小等操作的性能产生负面影响。

有没有人建议尽量减少这些核心内部表上的碎片?一个明显的解决方案可以避免创建如此多的表(或在 tempdb 中创建所有临时表),但对于这个问题,我们假设应用程序没有这种灵活性。

编辑:进一步的研究显示了这个悬而未决的问题,它看起来密切相关,并表明某种形式的手动维护ALTER INDEX...REORGANIZE可能是一种选择。


初步研究

可以在以下位置查看有关这些表的元数据sys.dm_db_partition_stats

-- The system base table that contains one row for every column in the system
SELECT row_count,
    (reserved_page_count * 8 * 1024.0) / row_count AS bytes_per_row, 
    reserved_page_count/128. AS space_mb
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('sys.syscolpars')
    AND index_id = 1
-- row_count:       15,600,859
-- bytes_per_row:   278.08
-- space_mb:        4,136
Run Code Online (Sandbox Code Playgroud)

但是,sys.dm_db_index_physical_stats似乎不支持查看这些表的碎片:

-- No fragmentation data is returned by sys.dm_db_index_physical_stats
SELECT *
FROM …
Run Code Online (Sandbox Code Playgroud)

sql-server fragmentation system-tables sql-server-2014

16
推荐指数
2
解决办法
3936
查看次数

查询在 SQL Server 2014 中慢 100 倍,行计数假脱机行估计罪魁祸首?

我有一个查询,它在SQL Server 2012中运行800 毫秒,在 SQL Server 2014中运行大约170 秒。我认为我已经将范围缩小到Row Count Spool运营商的基数估计不佳。我已经阅读了一些关于假脱机操作符的内容(例如,这里这里),但我仍然无法理解一些事情:

  • 为什么这个查询需要一个Row Count Spool运算符?我认为正确性没有必要,那么它试图提供什么特定的优化?
  • 为什么 SQL Server 估计到Row Count Spool操作符的连接会删除所有行?
  • 这是 SQL Server 2014 中的错误吗?如果是这样,我将在 Connect 中归档。但我想先有更深入的了解。

注意:我可以将查询重写为 aLEFT JOIN或向表添加索引,以便在 SQL Server 2012 和 SQL Server 2014 中实现可接受的性能。所以这个问题更多地是关于深入理解这个特定的查询和计划,而不是关于如何用不同的方式表达查询。


慢查询

请参阅此 Pastebin以获取完整的测试脚本。这是我正在查看的特定测试查询:

-- Prune any existing customers from the set of potential new customers
-- This query is much slower than …
Run Code Online (Sandbox Code Playgroud)

performance sql-server sql-server-2014 cardinality-estimates query-performance

13
推荐指数
3
解决办法
4673
查看次数

为什么批处理模式窗口聚合产量算术溢出?

以下查询SUM对列存储表执行窗口化处理1500 total rows,每个表的值为 0 或 1,并溢出INT数据类型。为什么会这样?

SELECT a, p, s, v, m, n,
    SUM(CASE WHEN n IS NULL THEN 0 ELSE 1 END)
        OVER (PARTITION BY s, v, a ORDER BY p) AS lastNonNullPartition
FROM (
    SELECT a, p, s, v, m, n,
        RANK() OVER (PARTITION BY v, s, a, p ORDER BY m) AS rank
    FROM #t /* A columnstore table with 1,500 rows */
)  x
WHERE x.rank = 1
--Msg 8115, …
Run Code Online (Sandbox Code Playgroud)

sql-server columnstore window-functions batch-mode sql-server-2016

12
推荐指数
1
解决办法
243
查看次数