powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Конкатенация большого количества значений
25 сообщений из 25, страница 1 из 1
Конкатенация большого количества значений
    #39621883
Фотография Big17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Коллеги, есть проблема производительности при конкатенации значений в переменную nvarchar(max)

Вот смотрите:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
	DECLARE @i int = 0
	DECLARE @Text nvarchar(max) = ''

	WHILE (@i < 10000)
	BEGIN
		SET @i = @i + 1
		SET @Text += 'ffffffffffffffffffffffffffffff'
	END



Если в строчке с присвоением внутри цикла указывать не 'ffffffffffffffffffffffffffffff', а 'ffff' (т.е. просто меньшее кол-во символов) - то производительность запроса изменяется в разы. То есть явное линейное падение производительности.

Это что же, сиквел при такой конкатенации вытаскивает все в память, выполняет операцию, а затем опять скидывает в кэш/на диск.
Т.е. не просто добавляет нужные символы к уже висящей в памяти переменной?

Собственно вопроса два:
1. Почему так происходит? (можете просто ссылкой кинуться в меня)
2. А есть ли альтернативные способы такой конкатенации?
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621895
Фотография Akina
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну в данном конкретном случае чего бы не попользовать REPLICATE()...
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621897
Фотография Big17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Дополнение: varchar(max) работает в разы быстрее nvarchar(max)
а nvarchar(4000) в десятки раз быстрее nvarchar(max)

Но мне нужна длинная строчка ((( порядка около 500 тыс. символов по итогу
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621900
Фотография Big17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AkinaНу в данном конкретном случае чего бы не попользовать REPLICATE()...
Да нет, в реальном то запросе там разные значения будут...
Это я для экспериментов в чистых условиях такой запрос наваял.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621909
AlanDenton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Тогда покажите все условия чтобы планируете реализовать через такую логику. Может там цикл и не нужен будет
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621912
Гигабайт Мегабайтович Килобайтов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
вы изучали какой нибудь язык программирования, который "в ручную" работает с памятью? ))
понимаете чем отличается char,nvarchar типы?
эти вопросы для того что, бы понять куда вас "ткнуть пальцем" ))
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621918
Фотография Big17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, я знаю особенности и различия char/nchar/varchar/nvarchar/max...

В реальной задаче у меня конечно же не цикл, а курсор, который формирует итоговый набор данных.
Но просадка по производительности именно в конкатенации.

Условия которые не обойти:
- не уложится в 4000 или в 8000 символов (даже внутри каждой итерации)


Сейчас нашел еще одно решение: вместо конкатенации вставляю значения во временную табличку, а затем из накопленных там строк формирую итоговую строчку.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
	SET NOCOUNT ON

	DECLARE @i int = 0
	DECLARE @SqlText nvarchar(max) = ''

	DECLARE @MyTableVar table(SqlText nvarchar(max))


	WHILE (@i < 10000)
	BEGIN

		SET @i = @i + 1

		SET @SqlText = 'ffffffffffffffffffffffffffffff'

		INSERT INTO @MyTableVar (SqlText)
		VALUES (@SqlText)

	END


	 SELECT @SqlText = STUFF((SELECT '' + [SqlText]
	  FROM @MyTableVar
	   for xml path('')) ,1,1, '' )

   SELECT LEN(@SqlText)



Работает заметно быстрее, даже на значительно больших количествах строк.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621919
iap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
DECLARE @Text nvarchar(max) = N'';
SET @Text=REPLICATE(CAST(N'ffffffffffffffffffffffffffffff' AS NVARCHAR(MAX)),10000);



P.S. Если не хотите писать N перед строками, то не используйте юникодный тип.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621926
iap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Big17Да, я знаю особенности и различия char/nchar/varchar/nvarchar/max...

В реальной задаче у меня конечно же не цикл, а курсор, который формирует итоговый набор данных.
Но просадка по производительности именно в конкатенации.

Условия которые не обойти:
- не уложится в 4000 или в 8000 символов (даже внутри каждой итерации)


Сейчас нашел еще одно решение: вместо конкатенации вставляю значения во временную табличку, а затем из накопленных там строк формирую итоговую строчку.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
	SET NOCOUNT ON

	DECLARE @i int = 0
	DECLARE @SqlText nvarchar(max) = ''

	DECLARE @MyTableVar table(SqlText nvarchar(max))


	WHILE (@i < 10000)
	BEGIN

		SET @i = @i + 1

		SET @SqlText = 'ffffffffffffffffffffffffffffff'

		INSERT INTO @MyTableVar (SqlText)
		VALUES (@SqlText)

	END


	 SELECT @SqlText = STUFF((SELECT '' + [SqlText]
	  FROM @MyTableVar
	   for xml path('')) ,1,1, '' )

   SELECT LEN(@SqlText)




Работает заметно быстрее, даже на значительно больших количествах строк.А зачем удаляете первый символ?
Вы же перед строкой ничего не добавляете!
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621928
AlanDenton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Big17 [src]В реальной задаче у меня конечно же не цикл, а курсор, который формирует итоговый набор данных.
Но просадка по производительности именно в конкатенации.
Покажите... ибо не понятна суть задачи что вы решаете. То что написано решается через REPLICATE. А делать замеры скорости дело неблагодарное для абстрактных задач.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621929
Фотография Big17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
N перед литералами практически не влияет на производительность в моем случае
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621931
Фотография Big17
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
AlanDentonBig17 [src]В реальной задаче у меня конечно же не цикл, а курсор, который формирует итоговый набор данных.
Но просадка по производительности именно в конкатенации.
Покажите... ибо не понятна суть задачи что вы решаете. То что написано решается через REPLICATE. А делать замеры скорости дело неблагодарное для абстрактных задач.


Да нет, в реальном то запросе там разные значения будут...
Это я для экспериментов в чистых условиях такой запрос наваял.


В реальной задаче у меня конечно же не цикл, а курсор, который формирует итоговый набор данных.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621934
iap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Big17N перед литералами практически не влияет на производительность в моем случаеВлияет на корректность преобразования VARCHAR() в NVARCHAR().
При чём здесь производительность?
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621935
iap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Big17В реальной задаче у меня конечно же не цикл, а курсор, который формирует итоговый набор данных.А по курсору-то циклом, небось, гуляете?
Прямой связи между циклом и курсором нет.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39621949
Гигабайт Мегабайтович Килобайтов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Big17Да, я знаю особенности и различия char/nchar/varchar/nvarchar/max...

В реальной задаче у меня конечно же не цикл, а курсор, который формирует итоговый набор данных.
Но просадка по производительности именно в конкатенации.

Условия которые не обойти:
- не уложится в 4000 или в 8000 символов (даже внутри каждой итерации)


Сейчас нашел еще одно решение: вместо конкатенации вставляю значения во временную табличку, а затем из накопленных там строк формирую итоговую строчку.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
	SET NOCOUNT ON

	DECLARE @i int = 0
	DECLARE @SqlText nvarchar(max) = ''

	DECLARE @MyTableVar table(SqlText nvarchar(max))


	WHILE (@i < 10000)
	BEGIN

		SET @i = @i + 1

		SET @SqlText = 'ffffffffffffffffffffffffffffff'

		INSERT INTO @MyTableVar (SqlText)
		VALUES (@SqlText)

	END


	 SELECT @SqlText = STUFF((SELECT '' + [SqlText]
	  FROM @MyTableVar
	   for xml path('')) ,1,1, '' )

   SELECT LEN(@SqlText)



Работает заметно быстрее, даже на значительно больших количествах строк.
таки не ответили на вопрос про языки программирования и работу с памятью )
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39622040
Massa52
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Big17,
Суммирование строк ваще тяжелая операция - зависит от способа организации строковых данных.
Это перегоняется масса байтов. Каждый раз при суммировании резервируется новый участок памяти и туда пузырятся обе строки. И если это в цикле - получается кошмар в цикле.
В VB.NET и с# для ускорения/оптимизации этой операции создан спецкласс StringBuilder.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39622384
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
	DECLARE @i int = 0
	DECLARE @Text nvarchar(max) = ''

	WHILE (@i < 10000)
	BEGIN
		SET @i = @i + 1
		SET @Text += 'ffffffffffffffffffffffffffffff'
	END




Это что же, сиквел при такой конкатенации вытаскивает все в память, выполняет операцию, а затем опять скидывает в кэш/на диск.

О чём ты, какой диск ? тут нет никаких операций с диском вообще.
Всё в памяти.

Т.е. не просто добавляет нужные символы к уже висящей в памяти переменной?

Именно так.

Собственно вопроса два:
1. Почему так происходит? (можете просто ссылкой кинуться в меня)
2. А есть ли альтернативные способы такой конкатенации?

1) потому.
2) нет.

У тебя просто происходит квадратичный взрыв объёма данных. 10000 * length('ffffffffffffffffffffffffffffff') (или length('ffff') ),
4 и 30.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39622433
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Big17В реальной задаче у меня конечно же не цикл, а курсор, который формирует итоговый набор данных.Курсор без цикла? Ооооо. :-)

Попытайтесь переделать ваш цикл в запрос, тогда будет быстрее, может быть.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39622435
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexeyvgПопытайтесь переделать ваш цикл в запрос, тогда будет быстрее, может быть.
Ой, не заметил, вы уже нашли:
Big17Сейчас нашел еще одно решение: вместо конкатенации вставляю значения во временную табличку, а затем из накопленных там строк формирую итоговую строчку.
Да, или так, или вообще вот это "формирую" сразу делать из исходных данных, без вставки во временную табличку.
Так сказать, работать с РСУБД именно как с РСУБД, операциями над множествами на платформе, созданной для этих операций.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39624113
лолл
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вместо цикла рекурсивное CTE не пробовали?
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39624134
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
лоллВместо цикла рекурсивное CTE не пробовали?Он уже нашёл вариант лучше.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39624204
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Massa52Big17,
Это перегоняется масса байтов. Каждый раз при суммировании резервируется новый участок памяти и туда пузырятся обе строки. И если это в цикле - получается кошмар в цикле.
В VB.NET и с# для ускорения/оптимизации этой операции создан спецкласс StringBuilder.
Это потому что в дотнете класс string - immutable, и конкатенация порождает новый экземпляр. В прочих случаях (например, в том же MSSQL) всё может быть совсем иначе.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39624333
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Конкатенация в памяти Windows намного медленнее конкатенации на диске.
Use it wisely.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39624402
Massa52
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
[quot Сон Веры Павловны]Massa52Big17,
Это потому что в дотнете класс string - immutable, и конкатенация порождает новый экземпляр. В прочих случаях (например, в том же MSSQL) всё может быть совсем иначе.

http://www.sqlservercentral.com/blogs/philfactor/2009/02/16/be-careful-with-string-concatenations-in-sql-server-with-big-strings/
Posted by RBarryYoung on 18 February 2009
It has long been known that naive linear string concatenation is an O(n^2) operation (more specifically, it's triangular). That simple fact is one of the big reasons that .NET has the StringBuilder class (which uses the strings->array->mass_concatenate trick that peter alludes to).

As it happens, I spent quite a lot of time last month investigating this problem and potential solutions and let me just say: it's tough in SQL. Here are the problems:

1) SQL Server apparently (based on my tests) already does the "buffer-extension" trick available to mutable strings. Unfortunately, the Extension trick does NOT solve the O(n^2) problem, it just partially alleviates it at the lower end because some percentage(k) of appends can be extensions instead of creating a new string. Effectively it changes the {(n)*(n+1)/2} cost of the naive implementation to {n +(n)*(n-1)/(2*k)} where "k" is that percentage. It's better, but it's still O(n^2).

2) The "array & mass-concatenate" trick is not available to T-SQL, not because SQL doesn't have arrays (tables serve the same purpose), but because AFAIK, there is no function that can take a variable "collection" of strings (table, array, whatever) and produce an output string.

3) The "pre-allocate and Stuff" trick popular with mutable strings is not workable in T-SQL because the STUFF() function in T_SQL is NOT like the function of the same name in some general purpose languages: the T-SQL STUFF() is an RHS (right-hand side) function and NOT an LHS (left-hand side) function. AFAIK, there is no function in SQL that can (physically) write into a pre-existing string.

That all said, I did eventually find a way to do it. Not in the O(n) time (linear) achievable in most general purpose languages, but I could get it down to O(n*Log(n)) time which is still a huge improvement. Unfortunately, I do not have it together in a presentable form and it would take me some time to do so (a day or so), but I can get it to you if you want.
...
Рейтинг: 0 / 0
Конкатенация большого количества значений
    #39624420
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Massa522) The "array & mass-concatenate" trick is not available to T-SQL, not because SQL doesn't have arrays (tables serve the same purpose), but because AFAIK, there is no function that can take a variable "collection" of strings (table, array, whatever) and produce an output string.
Дело не в отсутствии массивов - их вполне, начиная с 2008-й версии, можно заменить на UDTT, и написать свою функцию для конкатенации (другой вопрос, зачем это нужно, если посредством cross/outer apply можно прицепить конкатенацию через for xml path). Просто этот дотнетовский "array & mass-concatenate" trick - вовсе не trick: в StringBuilder в итоге конкатенация небольших объемов сводится к unsafe операциям с указателями, а на больших - вызывается managed-аналог сишного memmove (тоже, разумеется, unsafe). Т.е. сводится к прямой работе с памятью, которая, разумеется, в T-SQL недоступна.
...
Рейтинг: 0 / 0
25 сообщений из 25, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Конкатенация большого количества значений
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]