我正在尝试建立一个分页机制。我正在使用创建SQL的ORM,如下所示:
SELECT * FROM
(SELECT t1.colX, t2.colY
ROW_NUMBER() OVER (ORDER BY t1.col3) AS row
FROM Table1 t1
INNER JOIN Table2 t2
ON t1.col1=t2.col2
)a
WHERE row >= n AND row <= m
表1具有> 500k行,而表2具有> 10k记录
我直接在SQL Server 2008 R2 Management Studio中执行查询。子查询需要2-3秒才能执行,但整个查询需要> 2分钟。
我知道SQL Server 2012接受OFFSET .. LIMIT ..
选项,但我无法升级软件。
任何人都可以帮助我提高查询的性能或建议可以通过ORM软件施加的其他分页机制。
Update:
测试Roman Pekar的解决方案(请参阅解决方案的评论)证明ROW_NUMBER()可能不是导致性能问题的原因。不幸的是问题仍然存在。
由于
答案 0 :(得分:3)
我从评论中了解你的表结构。
create table Table2
(
col2 int identity primary key,
colY int
)
create table Table1
(
col3 int identity primary key,
col1 int not null references Table2(col2),
colX int
)
这意味着从Table1
返回的行永远不会被Table2
的联接过滤,因为Table1.col1
是not null
。由于Table2
是主键,因此Table2.Col2
的联接也不能向结果中添加行。
然后,您可以在加入Table1
之前重写查询以在Table2
生成行号。在联接到Table2
之前,也会应用where子句,这意味着您只能在Table2
中找到实际属于结果集的行。
select T1.colX,
T2.colY,
T1.row
from
(
select col1,
colX,
row_number() over(order by col3) as row
from Table1
) as T1
inner join Table2 as T2
on T1.col1 = T2.col2
where row >= @n and row <= @m
我不知道你是否可以使用你的ORM(Lightspeed by Mindscape)生成这样的分页查询,而不是你现在拥有的。
此答案的查询计划:
使用问题中的查询的查询计划:
两者之间的读取存在巨大差异。
答案 1 :(得分:1)
仅将分页表的主键列插入到具有标识列的临时表中,按排序列排序。 (您可能必须包含ordered-by列以确保排序正确。)然后,使用临时表作为所需行的键连接回主表。如果数据是相当静态的,您可以将订购数据保存到会话密钥的永久表而不是临时表,并在短时间内重复使用(因此几分钟内的后续页面请求几乎是即时的)。 / p>
Row_Number()往往在小数据集中表现良好,但是一旦你得到一些严重的行,就会遇到严重的性能障碍,就像你有500k一样。
答案 2 :(得分:0)
我建议您检查表格上的索引。如果您至少在col2
table2
上有索引,我认为这将有助于您的查询。您也可以尝试重写您的查询,如
;with cte1 as (
select top (@m) t1.colX, t2.colY, t1.col3
from Table1 as t1
inner join Table2 as t2 on t1.col1=t2.col2
order by t1.col3 asc
),
cte2 as (
select top (@m - @n + 1) *
from cte1
order by col3 desc
)
select *
from cte2 as t1
但如果您没有索引,它仍然可能会很慢