使用不同分页和 row_number 分页时的性能
Performance when using distinct and row_number pagination
我有一个 SQL 像这样的东西:
SELECT A,B,C,FUN(A) AS A FROM someTable
问题是 FUN()
是一个很慢的函数,所以如果 someTable
中有很多记录,就会有很大的性能问题。
如果我们使用分页,我们可以解决这个问题,我们这样做分页:
SELECT * FROM(
SELECT A,B,C,FUN(A), Row_number()OVER( ORDER BY B ASC) AS rownum FROM someTable
)T WHERE T.rownum >=1 AND T.rownum<20
在这个脚本中,FUN()
只会执行20次,所以性能还可以。
但是我们需要使用别名来排序,所以我们不能内联写rownum,必须移动到子查询或CTE,我们选择CTE,它看起来像这样:
;WITH CTE AS (
SELECT A,B AS alias,C,FUN(A) FROM someTable
)
SELECT * FROM(
SELECT *,Row_number()OVER( ORDER BY alias ASC) AS rownum FROM CTE
)T WHERE T.rownum >=1 AND T.rownum<20
到目前为止我们一切顺利,我们通过分页来解决性能问题,我们解决了别名顺序问题,但不知何故我们需要将 DISTINCT
添加到查询中:
;WITH CTE AS (
SELECT DISTINCT A,B AS alias,C,FUN(A) FROM someTable
)
SELECT * FROM(
SELECT *,Row_number()OVER( ORDER BY alias ASC) AS rownum FROM CTE
)T WHERE T.rownum >=1 AND T.rownum<20
在此之后,SQL 的优化似乎消失了,FUN()
将执行与 someTable
中的记录数一样多的次数,我们再次遇到性能问题。
基本都堵在这了,有什么建议吗?
问题在于,为了获得不同的值,数据库引擎必须 运行 对正在 select 编辑的所有记录执行 fun(a)
函数。
如果您只在最后的 select 中执行 fun(a)
,distinct
应该不会影响它,所以它应该只在最后的 20 条记录中执行 运行。
我已经将您使用的派生 table 更改为另一个 cte(但这是个人偏好 - 在我看来,不要混合派生 tables 和 ctes 更整洁):
;WITH CTE1 AS (
SELECT DISTINCT A,B AS alias,C
FROM someTable
),
CTE2 AS
(
SELECT *, ROW_NUMBER() OVER(ORDER BY alias) As RowNum
FROM CTE1
)
SELECT *, FUN(A)
FROM CTE2
WHERE RowNum >= 1
AND RowNum < 20
请注意,由于 fun
函数不确定,您可能会得到与原始查询不同的结果 - 因此在采用此解决方案之前,请先比较结果。
我有一个 SQL 像这样的东西:
SELECT A,B,C,FUN(A) AS A FROM someTable
问题是 FUN()
是一个很慢的函数,所以如果 someTable
中有很多记录,就会有很大的性能问题。
如果我们使用分页,我们可以解决这个问题,我们这样做分页:
SELECT * FROM(
SELECT A,B,C,FUN(A), Row_number()OVER( ORDER BY B ASC) AS rownum FROM someTable
)T WHERE T.rownum >=1 AND T.rownum<20
在这个脚本中,FUN()
只会执行20次,所以性能还可以。
但是我们需要使用别名来排序,所以我们不能内联写rownum,必须移动到子查询或CTE,我们选择CTE,它看起来像这样:
;WITH CTE AS (
SELECT A,B AS alias,C,FUN(A) FROM someTable
)
SELECT * FROM(
SELECT *,Row_number()OVER( ORDER BY alias ASC) AS rownum FROM CTE
)T WHERE T.rownum >=1 AND T.rownum<20
到目前为止我们一切顺利,我们通过分页来解决性能问题,我们解决了别名顺序问题,但不知何故我们需要将 DISTINCT
添加到查询中:
;WITH CTE AS (
SELECT DISTINCT A,B AS alias,C,FUN(A) FROM someTable
)
SELECT * FROM(
SELECT *,Row_number()OVER( ORDER BY alias ASC) AS rownum FROM CTE
)T WHERE T.rownum >=1 AND T.rownum<20
在此之后,SQL 的优化似乎消失了,FUN()
将执行与 someTable
中的记录数一样多的次数,我们再次遇到性能问题。
基本都堵在这了,有什么建议吗?
问题在于,为了获得不同的值,数据库引擎必须 运行 对正在 select 编辑的所有记录执行 fun(a)
函数。
如果您只在最后的 select 中执行 fun(a)
,distinct
应该不会影响它,所以它应该只在最后的 20 条记录中执行 运行。
我已经将您使用的派生 table 更改为另一个 cte(但这是个人偏好 - 在我看来,不要混合派生 tables 和 ctes 更整洁):
;WITH CTE1 AS (
SELECT DISTINCT A,B AS alias,C
FROM someTable
),
CTE2 AS
(
SELECT *, ROW_NUMBER() OVER(ORDER BY alias) As RowNum
FROM CTE1
)
SELECT *, FUN(A)
FROM CTE2
WHERE RowNum >= 1
AND RowNum < 20
请注意,由于 fun
函数不确定,您可能会得到与原始查询不同的结果 - 因此在采用此解决方案之前,请先比较结果。