SQL 数字的 CTE table 对于静态值来说很快,但对于 table 值来说很慢
SQL CTE for a numbers table is fast for static value, but slow for table value
我试图根据 table 中的列多次输出 table 的值。
我尝试使用 CTE 即时生成数字 table:
WITH cte AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (select 0)) AS i
FROM
sys.columns c1 CROSS JOIN sys.columns c2 CROSS JOIN sys.columns c3
)
select *
from myTable, cte
WHERE i <= myTable.timesToRepeatColumn
and myTable.id = '209386'
这个 SQL 似乎永远 运行,所以它似乎在加入之前试图 运行 整个 CTE。
如果我将 myTable.timesToRepeatColumn
替换为静态值(例如 10000),查询 returns 几乎是即时的。所以它似乎在完全交叉加入 CTE 的 table.
之前执行 where i <=
如何告诉 SQL 先执行 where 语句,就像它对静态数字所做的那样?
您可以使用递归 cte 来实现您的目标
WITH cte AS (
SELECT
*
, timesToRepeatColumn as level
FROM
myTablewhere
WHERE myTable.id = '209386'
UNION ALL
SELECT
*
, level -1 as level
FROM
cte
WHERE
level > 0
)
SELECT * FROM cte
SQL 服务器中的 CTE 不一定是 运行 'independently'。 SQL(在 SQL 服务器等中)是声明式的,这意味着您告诉它您想要什么,而不是如何去做。
如果查询优化器确定它可以通过做一些不同的事情来做得更好,它就会。
一个很好的例子是
IF EXISTS(SELECT * FROM test) PRINT 'X';
IF (SELECT COUNT(*) FROM test) > 0 PRINT 'Y';
IF (SELECT COUNT(*) FROM test) > 1 PRINT 'Z';
如果它按你说的做,第二个和第三个的查询计划基本上是一样的。但是,当你 运行 它时,第一个和第二个的查询计划是相同的;第三个不同。
当您 hard-code 值(例如 10,000)时,查询优化器可以使用该硬编码值来确定要执行的操作。在这种情况下,它可能确定它不需要 运行 完整的 CTE,只需 运行 它直到你得到 10,000 行。
但是,如果您使用一个可以变化的值(例如,myTable.timesToRepeatColumn),那么查询优化器通常会制定一个查询计划,该查询计划将使用 any 值.因此,它制定了一个不适合您的情况的查询计划 - 可能在使用它之前在内存中创建完整的 CTE。如果 sys.columns 有 100 行,那就是它创建的 100^3 行。如果是 1000,则为 1000^3,例如 1,000,000,000。您可能有超过 1000 行。
我试图根据 table 中的列多次输出 table 的值。
我尝试使用 CTE 即时生成数字 table:
WITH cte AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY (select 0)) AS i
FROM
sys.columns c1 CROSS JOIN sys.columns c2 CROSS JOIN sys.columns c3
)
select *
from myTable, cte
WHERE i <= myTable.timesToRepeatColumn
and myTable.id = '209386'
这个 SQL 似乎永远 运行,所以它似乎在加入之前试图 运行 整个 CTE。
如果我将 myTable.timesToRepeatColumn
替换为静态值(例如 10000),查询 returns 几乎是即时的。所以它似乎在完全交叉加入 CTE 的 table.
如何告诉 SQL 先执行 where 语句,就像它对静态数字所做的那样?
您可以使用递归 cte 来实现您的目标
WITH cte AS (
SELECT
*
, timesToRepeatColumn as level
FROM
myTablewhere
WHERE myTable.id = '209386'
UNION ALL
SELECT
*
, level -1 as level
FROM
cte
WHERE
level > 0
)
SELECT * FROM cte
SQL 服务器中的 CTE 不一定是 运行 'independently'。 SQL(在 SQL 服务器等中)是声明式的,这意味着您告诉它您想要什么,而不是如何去做。
如果查询优化器确定它可以通过做一些不同的事情来做得更好,它就会。
一个很好的例子是
IF EXISTS(SELECT * FROM test) PRINT 'X';
IF (SELECT COUNT(*) FROM test) > 0 PRINT 'Y';
IF (SELECT COUNT(*) FROM test) > 1 PRINT 'Z';
如果它按你说的做,第二个和第三个的查询计划基本上是一样的。但是,当你 运行 它时,第一个和第二个的查询计划是相同的;第三个不同。
当您 hard-code 值(例如 10,000)时,查询优化器可以使用该硬编码值来确定要执行的操作。在这种情况下,它可能确定它不需要 运行 完整的 CTE,只需 运行 它直到你得到 10,000 行。
但是,如果您使用一个可以变化的值(例如,myTable.timesToRepeatColumn),那么查询优化器通常会制定一个查询计划,该查询计划将使用 any 值.因此,它制定了一个不适合您的情况的查询计划 - 可能在使用它之前在内存中创建完整的 CTE。如果 sys.columns 有 100 行,那就是它创建的 100^3 行。如果是 1000,则为 1000^3,例如 1,000,000,000。您可能有超过 1000 行。