mrt*_*mrt 5 sql sql-server performance
我有一张有近3000万条记录的桌子.只有几个专栏.其中一列的值'Born'不超过30个,并且在其上定义了索引.我需要能够过滤该列并有效地翻阅结果.
现在我有(例如,如果我正在搜索的年份是'1970' - 它是我存储过程中的参数):
WITH PersonSubset as
(
SELECT *, ROW_NUMBER() OVER (ORDER BY Born asc) AS Row
FROM Person WITH (INDEX(IX_Person_Born))
WHERE Born = '1970'
)
SELECT *, (SELECT count(*) FROM PersonSubset) AS TotalPeople
FROM PersonSubset
WHERE Row BETWEEN 0 AND 30
Run Code Online (Sandbox Code Playgroud)
该排序的每个查询(仅Born使用参数)仅返回超过100万个结果.我注意到最大的开销是用于返回总结果的计数.如果我(SELECT count(*) FROM PersonSubset) AS TotalPeople从select子句中删除整个事情会加速很多.
有没有办法加快该查询中的计数.我关心的是返回分页结果和总计数.
更新了以下评论中的讨论
这里的问题的原因是非常低的基数中的IX_Person_Born索引.
SQL索引非常适合快速缩小值,但是当您有大量具有相同值的记录时,它们会出现问题.
您可以将其视为电话簿的索引 - 如果您想要找到"史密斯,约翰",您首先会发现有许多以S开头的名称,然后是名为史密斯的页面和页面,然后很多约翰斯.你最终扫描了这本书.
这是复杂的,因为电话簿中的索引是聚集的 - 记录按姓氏排序.如果你想要找到所谓的"约翰",你会做很多的查找.
这里有3000万条记录,但只有30个不同的值,这意味着最好的索引仍然可以返回大约100万条记录 - 在这种规模上它也可能是一个表扫描.这100万个结果中的每一个都不是实际记录 - 它是从索引到表格的查找(电话簿类比中的页码),这使得它更慢.
高基数指数(比如说出生日期),而不是年份会快得多.
这是所有OLTP关系数据库的一般问题:low cardinality + huge datasets = slow queries因为索引树没有多大帮助.
简而言之:使用T-SQL和索引获取计数没有明显更快捷的方法.
你有几个选择:
OLAP/Cube汇总或自行完成:
select Born, count(*)
from Person
group by Born
Run Code Online (Sandbox Code Playgroud)
专家是多维数据集查找或检查您的缓存非常快.问题是数据会过时,你需要一些方法来解决这个问题.
分为两个查询:
SELECT count(*)
FROM Person
WHERE Born = '1970'
SELECT TOP 30 *
FROM Person
WHERE Born = '1970'
Run Code Online (Sandbox Code Playgroud)
然后在并行服务器端运行它们,或将其添加到用户界面.
这个问题是无SQL解决方案相对于传统关系数据库的一大优势.在无SQL系统中,Person表是在许多廉价服务器上联合(或分片)的.当用户搜索每个服务器时同时进行检查.
此时技术变革可能已经结束,但可能值得调查,所以我已将其纳入其中.
我过去曾遇到类似问题的这种大小的数据库,并且(取决于上下文)我已经使用了选项1和2.如果这里的总数是分页,那么我可能选择2和AJAX打电话来计算.
DECLARE @TotalPeople int
--does this query run fast enough? If not, there is no hope for a combo query.
SET @TotalPeople = (SELECT count(*) FROM Person WHERE Born = '1970')
WITH PersonSubset as
(
SELECT *, ROW_NUMBER() OVER (ORDER BY Born asc) AS Row
FROM Person WITH (INDEX(IX_Person_Born))
WHERE Born = '1970'
)
SELECT *, @TotalPeople as TotalPeople
FROM PersonSubset
WHERE Row BETWEEN 0 AND 30
Run Code Online (Sandbox Code Playgroud)
通常不能将慢速查询与快速查询结合起来,最后得到快速查询。
其中一列“Born”的不同值不超过 30 个,并且在其上定义了一个索引。
SQL Server 没有使用索引或统计信息,或者索引和统计信息没有足够的帮助。
这是一个绝望的措施,将迫使 Sql 采取行动(潜在的代价是使写入变得非常昂贵 - 测量这一点,并在视图存在时阻止对 Person 表的架构更改)。
CREATE VIEW dbo.BornCounts WITH SCHEMABINDING
AS
SELECT Born, COUNT_BIG(*) as NumRows
FROM dbo.Person
GROUP BY Born
GO
CREATE UNIQUE CLUSTERED INDEX BornCountsIndex ON BornCounts(Born)
Run Code Online (Sandbox Code Playgroud)
通过在视图上放置聚集索引,可以使其成为系统维护的副本。该副本的大小远小于 3000 万行,并且包含您正在查找的确切信息。我不必更改查询来使其使用视图,但如果您愿意,您可以在查询中自由使用视图的名称。
| 归档时间: |
|
| 查看次数: |
12739 次 |
| 最近记录: |