在SQL Server 2008端,我有表值函数,它接收合并到单VARBINARY(MAX)
的45k整数id,将它们拆分并作为表返回。 SplitIds
最多需要5秒。正如我在估计执行计划中看到的那样 - 100%是'表插入'。有可能以某种方式加速这个功能吗?
ALTER FUNCTION [dbo].[SplitIds](@data VARBINARY(MAX))
RETURNS @result TABLE(Id INT NOT NULL)
AS
BEGIN
IF @data IS NULL
RETURN
DECLARE @ptr INT = 0, @size INT = 4
WHILE @ptr * @size < LEN(@data)
BEGIN
INSERT INTO @result(Id)
VALUES(SUBSTRING(@data, @ptr * @size + 1, @size))
SET @ptr += 1
END
RETURN
END
目前在C#端,它以下一种方式用于Linq-to-SQL查询:
XDbOrder[] orders =
database.SplitIds(ConvertToVarbinary(orderIds))
Join(
database.Get<XDbOrder>,
r = r.Id,
o => o.Id,
(r, o) => o).
ToArray();
更一般的问题:在Linq-to-SQL中,以某种方式实现下一个没有SplitIds
的东西是否可能? .Contains
不起作用 - 它创建的查询包含超过2100个SQL参数和崩溃。
int[] orderIds = { ... 45k random entries .....};
XDbOrder[] orders =
database.Get<XDbOrder>().
Where(o => orderIds.Contains(o.Id)).
ToArray();
答案 0 :(得分:4)
您可以尝试更基于集合的方法。
(我保留了多语句TVF方法,因为生成数字表的内联方法很好地隔离,但是当合并到更大的查询中时执行计划可能非常糟糕 - 这确保了分裂发生一次,只发生过一次)
我还在返回表中添加了一个主键,因此它包含一个有用的索引。
CREATE FUNCTION [dbo].[SplitIds](@data VARBINARY(MAX))
RETURNS @result TABLE(Id INT NOT NULL PRIMARY KEY WITH (IGNORE_DUP_KEY=ON))
AS
BEGIN
IF @data IS NULL
RETURN
DECLARE @size INT = 4;
WITH E1(N)
AS (SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1), -- 1*10^1 or 10 rows
E2(N)
AS (SELECT 1 FROM E1 a, E1 b), -- 1*10^2 or 100 rows
E4(N)
AS (SELECT 1 FROM E2 a, E2 b), -- 1*10^4 or 10,000 rows
E8(N)
AS (SELECT 1 FROM E4 a, E4 b), -- 1*10^8 or 100,000,000 rows
Nums(N)
AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1
FROM E8)
INSERT INTO @result
(Id)
SELECT TOP (DATALENGTH(@data)/@size) SUBSTRING(@data, N * @size + 1, @size)
FROM Nums
RETURN
END
以下为我完成约160ms
DECLARE @data VARBINARY(MAX) = 0x
WHILE DATALENGTH(@data) < 184000
SET @data = @data + CRYPT_GEN_RANDOM(8000)
SELECT COUNT(*)
FROM [dbo].[SplitIds](@data)
答案 1 :(得分:0)
这是我基于集合的方法的版本
load
关于我的方法的几点说明
load:function(me, node) {
if(node && node.attributes.checked) node.cascade(
... [function to check all children]
)
}
将避免create FUNCTION [dbo].[SplitIds1](@data VARBINARY(MAX))
returns table with SCHEMABINDING
as
return
WITH e1(n) AS
(
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), -- 10
e2(n) AS (SELECT 1 FROM e1 CROSS JOIN e1 AS b), -- 10*10
e3(n) AS (SELECT 1 FROM e1 CROSS JOIN e2), -- 10*100
e4(n) AS (SELECT 1 FROM e3 A CROSS JOIN e3 B), -- 1000*1000
Numbers(ptr,Size) AS (SELECT ROW_NUMBER() OVER (ORDER BY n)-1,4 FROM e4)
SELECT SUBSTRING(@data, ptr * Size + 1, Size) as Id
FROM Numbers
WHERE ptr * Size < LEN(@data)
SCHEMABINDING
运算符
Table
spool
变量,因为它在函数内部是硬编码的execution plan
表值函数更改为@size
表值函数,它允许您在函数内部查看Multi-Statement
select语句,就像任何Inline
或{{1}一样查询