考虑一个总是单调增加的值的 B 树索引,例如 IDENTITY 类型的列。使用传统的 B 树实现,每当节点已满时,它将被拆分 50%/50%,我们最终得到一个 B 树,其中(几乎)所有节点都只有 50% 已满。
我知道 Oracle 会发现值何时不断增加,在这些情况下,Oracle 会执行 90%/10% 的拆分。这样,(几乎)所有节点都将充满 90%,并且对于这些非常常见的情况,可以获得更好的页面利用率。
我无法在 SQL Server 中找到类似功能的文档。但是,我进行了两次实验,分别在索引中插入了 N 个随机整数和 N 个连续整数。前一种情况使用了更多的页面,后者。
SQL Server 是否提供类似的功能?如果是这样:你能指点我一些关于这个功能的文档吗?
更新: 通过下面提供的实验,似乎叶节点保持未分裂,内部节点分裂 50%/50%。这使得增加键上的 B 树比随机键上的更紧凑。然而,Oracle 的 90%/10% 方法甚至更好,我仍然在寻找一些官方文档来验证实验中看到的行为。
大学 SQL 课程,使用 John J. Patrick 所著的“SQL Fundamentals”一书。在第三章中,他谈到使用“常量表”向 select 语句添加列,其中所有行都具有相同的值。
例如,如果您有表“字符”,如下所示:
first_name last_name dept_code
----------- ---------- -------------------
Fred Flintstone ROCKS
Barney Rubble ROCKS
Wilma Flintstone FACEPALMING_AT_FRED
Run Code Online (Sandbox Code Playgroud)
并且您想要一个 SELECT 向所有行添加值为“BEDROCK”的列“hometown”,他建议在数据库中创建第二个表“temp”,
hometown
--------
BEDROCK
Run Code Online (Sandbox Code Playgroud)
然后做
SELECT first_name, last_name, dept_code, hometown FROM characters, temp
Run Code Online (Sandbox Code Playgroud)
这个想法是避免将字符串常量放在 SELECT 语句中,并且如果您有很多需要相同常量的 SELECT,更新一个表比更新 50 个查询更容易。
问题是,过去 15 年来我一直在使用 SQL 数据库,但我从未见过这种结构。它是我刚刚错过的完全常见的东西,还是在这个任务结束后我可以从我的记忆中抹去的东西?
除了在下面给定的 SP 中使用 IN 子句之外,还有没有更好的方法来编写 SQL。当我使用这个 IN 子句时,由于 User 和 Member 表中涉及大量或记录,我的性能下降。
CREATE PROCEDURE [dbo].[sp_MemberIdsFromUserIds] @dtUserIds UNIQUETABLE readonly
AS
BEGIN
SELECT userID,
Memberid
FROM Member
INNER JOIN USER
ON UserMemberID = MemberiD
WHERE userID IN (SELECT UniqueId
FROM @dtUserIds)
END
Run Code Online (Sandbox Code Playgroud)
请提出替代方案,因为我对写作 SP 没有完整的了解
我们有一个严重碎片化的客户数据库——实际上每个超过 1000 页的表都有 >95% 的碎片。填充因子设置为合理的值,但页面空间使用量远不及大多数表的填充因子。
这是没有对数据库执行维护的结果。
使用Ola Hallengren 的 IndexOptimize重建索引可按预期减少碎片。在现有的生产硬件上,应用程序的性能按预期提高。我通常使用的所有指标——大量查询的客户端统计、分析器持续时间、读/写停顿、应用程序日志和用户感知——都表明性能得到了提高。
然而,支持英特尔 PCIe SSD 的新数据库服务器显示出与我们预期相反的情况。高度分散,应用程序运行良好。重建索引后,应用程序性能不佳。一些需要约 90 秒的操作现在需要约 6 分钟。但是,其他指标似乎都没有表明系统运行速度变慢。
这是其他人经历过的吗?
这里我们有两个类似的查询,使用grouping sets
whereSELECT子句包含一些在聚合中计算的表达式:
SELECT RN10, RN10 / 10, COUNT(*) FROM
(
SELECT RN, RN/10 AS RN10, RN/100 AS RN100 FROM
(
SELECT RN = -1 + ROW_NUMBER() OVER (ORDER BY 1/0)
FROM master..spt_values
) A
) B
GROUP BY GROUPING SETS ((RN10), (RN10 / 10), ())
ORDER BY 1, 2
Run Code Online (Sandbox Code Playgroud)
它的计划在这里:第一个查询计划
和
SELECT RN10, SUBSTRING(RN,3,99), COUNT(*) FROM
(
SELECT RN, SUBSTRING(RN,2,99) AS RN10 FROM
(
SELECT RN = CAST(-1 + ROW_NUMBER() OVER (ORDER BY 1/0) AS …Run Code Online (Sandbox Code Playgroud) 我在为此创建的博客文章中解释了我遇到的问题(易于参考和管理 1 个位置的响应/解决方案),可在此处找到:http : //schoennie.blogspot.com/ 2013/09/slow-statman-query-issue-with-sp2010.html
简短的总结是,在 SQL 2008R2(同一服务器)之上安装 SharePoint 2010 的单个服务器在特定时间间隔内(似乎是每天早上)在每次第一次上传时都遇到非常缓慢的响应。分析 SQL 活动后,我发现当您开始上传时,此查询会在上传的“插入部分”之前执行:
SELECT StatMan([SC0], [LC0])
FROM (SELECT TOP 100 PERCENT CONVERT(VARBINARY,
SUBSTRING ([Content], 1, 100) +
+SUBSTRING([Content], CASE
WHEN LEN([Content]) <= 200 THEN 101
ELSE LEN([Content]) - 99
END, 100)) AS [SC0],
DATALENGTH([Content]) AS [LC0]
FROM [dbo].[AllDocStreams] WITH (READUNCOMMITTED)
ORDER BY [SC0]) AS _MS_UPDSTATS_TBL
Run Code Online (Sandbox Code Playgroud)
我现在花了几天时间试图获得有关此 StatMan 查询的更多信息,以及为什么它会导致磁盘 i/o 通过屋顶和磁盘队列长度增长到 5 值以上(通常约为 0.01)
请分享您对此的想法,或者为我指明某个方向/资源?我在这个软件领域作为 SharePoint 顾问和 DBA 参与了大约 8 年,但我还没有见过这样的事情!
非常感谢,杰罗恩
我发现相同的查询在不同的 DBMS 中不起作用令人沮丧。
例如,某些 DBMS(例如 Microsoft SQL Server 和 MySQL)似乎支持该information_schema表,而其他DBMS(例如SQLite)则不支持。
一些数据库如 MySQL 允许你做SHOW TABLES,等等。
有些限制使用结果,SELECT TOP 10 ...而其他限制使用... LIMIT 10.
为什么不同的 DBMS 如此不兼容和异常?
他们为什么不遵循 SQL 标准?
哪些擅长坚持SQL标准?
哪些在遵守 SQL 标准方面是出了名的差?
我有一个表,对于一组给定的字段 a、b 和 c,我需要获取按 d 和 e 排序的第一行和最后一行,并且正在使用 ROW_NUMBER 来获取这些行。声明的相关部分是...
ROW_NUMBER() OVER (PARTITION BY a,b,c ORDER BY d ASC, e ASC) AS row_number_start,
ROW_NUMBER() OVER (PARTITION BY a,b,c ORDER BY d DESC, e DESC) AS row_number_end
Run Code Online (Sandbox Code Playgroud)
执行计划显示了两个排序操作,每个操作一个。这些排序操作占语句总成本的 60% 以上(我们在这里谈论的是数千万行,分区通常每个分区有 1-100 条记录,大部分在 10 条以下)
所以如果我能摆脱其中的一个就好了。我试图创建一个索引来复制排序;这消除了排序操作之一,但没有消除后者。(请注意,创建的任何索引仅用于此过程,并且会作为 ETL 过程的一部分每天重新创建。)
从检查执行计划来看,我认为问题是在执行partition by语句时,SQL Server坚持按分区列升序排序。从逻辑上讲,是升序还是降序都没有关系,如果优化器理解这一点,那么它可以向后读取相同的索引来计算 row_number_end。
有什么方法可以让优化器在这里看到意义,或者有人可以建议另一种方法来实现相同的最终目标吗?
下面是我在生产中遇到的事情的简化版本(在处理异常大量批次的一天,计划变得灾难性地更糟)。
已使用新的基数估计器针对 2014 年和 2016 年对 repro 进行了测试。
CREATE TABLE T1 (FromDate DATE, ToDate DATE, SomeId INT, BatchNumber INT);
INSERT INTO T1
SELECT TOP 1000 FromDate = '2017-01-01',
ToDate = '2017-01-01',
SomeId = ROW_NUMBER() OVER (ORDER BY @@SPID) -1,
BatchNumber = 1
FROM master..spt_values v1
CREATE TABLE T2 (SomeDateTime DATETIME, SomeId INT, INDEX IX(SomeDateTime));
INSERT INTO T2
SELECT TOP 1000000 '2017-01-01',
ROW_NUMBER() OVER (ORDER BY @@SPID) %1000
FROM master..spt_values v1,
master..spt_values v2
Run Code Online (Sandbox Code Playgroud)
T1 包含 1,000 行。
的FromDate,ToDate …
我有一个案例,我正在运行的查询需要很长时间。当我检查sys.dm_exec_requests它blocking_session_id是一个负值时,具体来说是-2。等待是一个LCK_M_X,阻塞的命令是一个DELETE语句。据我所知,目前没有其他东西触及那张桌子。事实上,唯一的活动请求是被阻止的连接和查询检查sys.dm_exec_requests。当我查看sys.dm_tran_session_transactions被阻止的会话时,只有一个出现。
sql-server ×7
index ×2
blocking ×1
group-by ×1
optimization ×1
page-splits ×1
performance ×1
sharepoint ×1
sql-standard ×1
statistics ×1