向临时表添加索引会导致单行结果集

时间:2016-05-28 13:10:52

标签: sql sql-server temp-tables

在sp_executesql中,select语句用于连接变量本身和临时表中列的值。

当我将索引应用于此临时表并在上述select语句中使用排序时,这会产生奇怪的结果。

仅当临时表的行数大于50行时才会发生这种情况。

我不喜欢粘贴大代码示例,但我无法进一步减少它。

如果@maxjob> = 8,则生成的@htmllog包含67个字符。这是一个意想不到的结果。

如果@maxjob< 8,然后生成的@htmllog总是包含超过67个字符。这是预期的结果。

此外,

当我从#acl_log表中删除索引idx_key时,当@maxjob> = 8时问题就消失了。 要么 当我从@executesql_sql中删除'order by [key] asc'时,问题也会消失。

为什么?

declare @logtable as varchar(max)
set @logtable = '#acl_log'

if (OBJECT_ID('[tempdb]..#acl_log')) is not null
    drop table #acl_log

create table #acl_log(
    [key]       int             identity,
    [message]   nvarchar(max)   not null,
    index idx_key ([key])
)

declare @job as int
declare @maxjob as int

set @job = 0
set @maxjob = 8

while (@job < @maxjob + 1)
begin
    insert into #acl_log([message])
    values
        ('Internet Explorer is currently running without add-ons')
        ,('All Internet Explorer add-ons, such as ActiveX controls or toolbars, are turned off. Some webpages might not display correctly.')
        ,('To continue to your home page, click the Home button.')
        ,('To browse using add-ons, close Internet Explorer and then start it again.')
        ,('Forward Arrow  Check for the latest Windows updates. ')
        ,('Question Icon How do browser add-ons affect my browsing experience? ')

    set @job = @job + 1
end

declare @executesql_sql as nvarchar(max)
declare @executesql_param as nvarchar(max)

declare @htmllog as varchar(max)
set @executesql_sql = '
    set @htmllog = ''''
    select @htmllog = @htmllog + [message]
    from ' + @logtable + '
    order by [key] asc'
set @executesql_param = '@htmllog varchar(max) output'

exec master..sp_executesql @executesql_sql, @executesql_param, @htmllog = @htmllog output

select len(@htmllog), @htmllog

1 个答案:

答案 0 :(得分:3)

聚合字符串连接的行为未定义,因为它根据Microsoft在this connect item中的注释而依赖于计划:

  

即使没有ORDER BY,我们也不保证@v​​ar = @var +    将为任何语句生成连接值   这会影响多行。表达式的右侧可以   在查询执行期间进行一次或多次评估   我所说的行为取决于计划。

一种解决方法是FOR XML子句:

DECLARE @logtable AS varchar(MAX);
SET @logtable = '#acl_log';

IF (OBJECT_ID('[tempdb]..#acl_log')) IS NOT NULL
    DROP TABLE #acl_log;

CREATE TABLE #acl_log(
    [key]       int             IDENTITY,
    [message]   nvarchar(max)   not null,
    INDEX idx_key ([key])
);

DECLARE @job as int;
DECLARE @maxjob as int;

SET @job = 0;
SET @maxjob = 8;

WHILE (@job < @maxjob + 1)
BEGIN
    INSERT INTO #acl_log([message])
    VALUES
        ('Internet Explorer is currently running without add-ons')
        ,('All Internet Explorer add-ons, such as ActiveX controls or toolbars, are turned off. Some webpages might not display correctly.')
        ,('To continue to your home page, click the Home button.')
        ,('To browse using add-ons, close Internet Explorer and then start it again.')
        ,('Forward Arrow  Check for the latest Windows updates. ')
        ,('Question Icon How do browser add-ons affect my browsing experience? ');

    SET @job = @job + 1;
END

DECLARE @executesql_sql AS nvarchar(MAX);
DECLARE @executesql_param AS nvarchar(MAX);

DECLARE @htmllog AS varchar(max);
SET @executesql_sql = '
    SET @htmllog = (SELECT [message]
    FROM ' + @logtable + '
    ORDER BY [key]
    FOR XML PATH(''''), TYPE).value(''.'', ''varchar(MAX)'');';

set @executesql_param = '@htmllog varchar(max) OUTPUT';

EXEC master..sp_executesql @executesql_sql, @executesql_param, @htmllog = @htmllog output;

SELECT LEN(@htmllog), @htmllog;
GO