Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Lukich
Member

Откуда: Зелик
Сообщений: 275
Доброго дня!
Коллеги, уперся по производительности в 2 тыс. Batch Requests / sec.
Может будут полезные советы, как найти узкое место? (ускориться надо бы раза в 2)

Что имеем (Microsoft SQL Server 2012 (SP1) - 11.0.3000.0 (X64) Standard Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: )):
* идут массированые вставки и обновления в таблицы, со средним соотношением на 1 вставку - 5 обновлений
* для бОльшей производительности вставки/обновления производятся в 5 потоков и идут пачками по 10 тыс. на транзакцию (пробовал менять кол-во потоков от 1 до 64 и кол-во операций на транзакцию от 1 до 100 тыс.)
* база лежит на RAM диске (recovery simple)
* Processor Time 10-15%
* Database IO 7-20 MB/s
* Waiting Tasks 1-3 (похоже тут нужно копать, но как?)
28 май 13, 10:33    [14357572]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests  [new]
Glory
Member

Откуда:
Сообщений: 104751
Lukich
для бОльшей производительности вставки/обновления производятся в 5 потоков

А эти ваши 5 потоков могут продуцировать больше 2000 именно батчей ?
28 май 13, 10:52    [14357734]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
радикал радикалович
Guest
Lukich
Доброго дня!
Коллеги, уперся по производительности в 2 тыс. Batch Requests / sec.
Может будут полезные советы, как найти узкое место? (ускориться надо бы раза в 2)

Что имеем (Microsoft SQL Server 2012 (SP1) - 11.0.3000.0 (X64) Standard Edition (64-bit) on Windows NT 6.2 <X64> (Build 9200: )):
* идут массированые вставки и обновления в таблицы, со средним соотношением на 1 вставку - 5 обновлений
* для бОльшей производительности вставки/обновления производятся в 5 потоков и идут пачками по 10 тыс. на транзакцию (пробовал менять кол-во потоков от 1 до 64 и кол-во операций на транзакцию от 1 до 100 тыс.)
* база лежит на RAM диске (recovery simple)
* Processor Time 10-15%
* Database IO 7-20 MB/s
* Waiting Tasks 1-3 (похоже тут нужно копать, но как?)


добавь ddl таблицы с индексами куда льется/обновляется, а так же сами запросы на обновления/вставку.

если бы не update, можно было бы глядеть также в сторону bcp api. и делать массовые вливы.
28 май 13, 12:39    [14358535]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Lukich
Member

Откуда: Зелик
Сообщений: 275
Glory
А эти ваши 5 потоков могут продуцировать больше 2000 именно батчей ?

Если вместо вставок/обновления делать RETURN, то генерится >3 тыс. батчей
Может порекомендуете настройку чтобы сервер более напряженно трудился? (в ущерб отказоустойчивости)
28 май 13, 13:01    [14358758]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests  [new]
Glory
Member

Откуда:
Сообщений: 104751
Lukich
Если вместо вставок/обновления делать RETURN, то генерится >3 тыс. батчей

А вы батчем называете какое количество команд ?
28 май 13, 13:02    [14358779]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Lukich
Member

Откуда: Зелик
Сообщений: 275
Glory,
1 батч = 1 вызов процедуры на вставку/обновление
в рамках 1 транзакции - 10 тыс. батчей из 5 потоков (коннектов)
28 май 13, 13:41    [14359112]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests  [new]
Glory
Member

Откуда:
Сообщений: 104751
Lukich
1 батч = 1 вызов процедуры на вставку/обновление

А процедуре десяток команд ?

Lukich
в рамках 1 транзакции - 10 тыс. батчей из 5 потоков (коннектов)

Ммм, а как это вы одну транзакцию на 5 коннектов сделали ?
28 май 13, 13:43    [14359135]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Гавриленко Сергей Алексеевич
Member

Откуда:
Сообщений: 37254
Раз есть ресурсы, то сделайте 10, 20, 50 потоков.
28 май 13, 13:46    [14359160]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Lukich
Member

Откуда: Зелик
Сообщений: 275
Glory
Lukich
1 батч = 1 вызов процедуры на вставку/обновление

А процедуре десяток команд ?

Lukich
в рамках 1 транзакции - 10 тыс. батчей из 5 потоков (коннектов)

Ммм, а как это вы одну транзакцию на 5 коннектов сделали ?


Да, данные раскидываются по разным таблицам.
Пардон, потоков 5, но работают они через единый SqlConnection
28 май 13, 13:52    [14359204]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests  [new]
Glory
Member

Откуда:
Сообщений: 104751
Lukich
Пардон, потоков 5, но работают они через единый SqlConnection

Это 5 коннектов. Они не работают через один SqlConnection, они созданы на основе одного SqlConnection

Lukich
Да, данные раскидываются по разным таблицам.

Непонятно, что вы тогда меряете через Batch Requests / sec, если за каждым батчем у вас десяток команд.
28 май 13, 13:55    [14359225]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
aleks2
Guest
Lukich
Пардон, потоков 5, но работают они через единый SqlConnection

Все чудесатее и чудесатее! (с) Алиса в стране чудес.
28 май 13, 13:56    [14359230]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Lukich
Member

Откуда: Зелик
Сообщений: 275
Glory
Lukich
Пардон, потоков 5, но работают они через единый SqlConnection

Это 5 коннектов. Они не работают через один SqlConnection, они созданы на основе одного SqlConnection

Lukich
Да, данные раскидываются по разным таблицам.

Непонятно, что вы тогда меряете через Batch Requests / sec, если за каждым батчем у вас десяток команд.


Проверил профайлером все сохранения в базу происходит с единого SPID((

Поясню то что я меряю, производится построчный разбор на поля текстового лога и сохранение в базу, причем "Batch Requests / sec" полностью коррелирует с производительностью обработки данных - 2000 Batch Requests / sec соответствует 1700 строчкам лога.
Дело в том, что большинство команд из процедуры вставки/обновления вызываются редко (например, если параметр {Значение из справочника} пустой, то и обращение к соответствующей таблице-справочнику не происходит)

Чтобы было понятно, все выглядит так (упрощенно):
public class File2Db: IDisposable
{
	public readonly DbHelper DbHelper = new DbHelper();
	
	public void Go(string logFile)
	{        
		var sr = new StreamReader(fileFullName);
		var parallelBuffer = new List<string>();
		DbHelper.SqlTransaction = DbHelper.SqlConnection.BeginTransaction();

		while (sr.Peek() != -1)
		{
			string line = sr.ReadLine();
			++rows;
			parallelBuffer.Add(line);
			if (parallelBuffer.Count == 5)//ПАРАЛЛЕЛИМ ОБРАБОТКУ
			{
				ProccessParallelBuffer(parallelBuffer);
				if (rows % 10000 == 0)
				{
					DbHelper.SqlTransaction.Commit();//ЗАКРЫВАЕМ ТРАНЗАКЦИЮ
					DbHelper.SqlTransaction = DbHelper.SqlConnection.BeginTransaction();
				}				
			}
		}
		...
	}

	private void ProccessParallelBuffer(ICollection<string> parallelBuffer)
	{
		var parallelOptions = new ParallelOptions
			{
				MaxDegreeOfParallelism = parallelBuffer.Count
			};
		Parallel.ForEach(parallelBuffer, parallelOptions, line =>
			{
				var parsedLine = new LogParser.ParsedLine(line);
				Save(parsedLine);
			}
		); 			
		parallelBuffer.Clear();
	}

	private void Save(ParsedLine parsedLine)
	{
		var sqlCommand = new SqlCommand(@"Save", DbHelper.SqlConnection) { CommandType = CommandType.StoredProcedure };
		sqlCommand.Transaction = DbHelper.SqlTransaction;//в рамках транзакции
		sqlCommand.Parameters.Add(new SqlParameter("LineNo", ParsedLine.LineNo));//+ еще порядка 30 параметров
		...
		sqlCommand.ExecuteNonQuery();
	}
}

public class DbHelper : IDisposable //для работы с базой
{
	public SqlConnection SqlConnection;
	public SqlTransaction SqlTransaction;
	public DbHelper(bool open = true)
	{
		if (open)
		{
			SqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlConnection"].ConnectionString);
			SqlConnection.Open();
		}
	}

	void IDisposable.Dispose()
	{
		SqlConnection.Dispose();
	}	
	...
}		
28 май 13, 15:37    [14360011]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests  [new]
Glory
Member

Откуда:
Сообщений: 104751
Lukich
Поясню то что я меряю, производится построчный разбор на поля текстового лога и сохранение в базу, причем "Batch Requests / sec" полностью коррелирует с производительностью обработки данных - 2000 Batch Requests / sec соответствует 1700 строчкам лога.


A batch is a group of one or more Transact-SQL statements sent at the same time from an application to SQL Server for execution. SQL Server compiles the statements of a batch into a single executable unit, called an execution plan. The statements in the execution plan are then executed one at a time.

Вы уверяете, что у вас "1 батч = 1 вызов процедуры на вставку/обновление" и внутри "десяток команд"

Lukich
Проверил профайлером все сохранения в базу происходит с единого SPID((

Про какие тогда 5 параллельных потоков вы говорите ?
28 май 13, 15:42    [14360047]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
радикал радикалович
Guest
Lukich,

Судя коду,

Parallel.ForEach(parallelBuffer, parallelOptions, line =>
{
var parsedLine = new LogParser.ParsedLine(line);
Save(parsedLine);
}


Распараллеливается оно с помощью PLINQ, но все потоки щимятся в один коннекшн. Далее читаем доку о потокобезопасности SqlConnection.


http://msdn.microsoft.com/ru-ru/library/system.data.sqlclient.sqlconnection.aspx

SqlConnection Любые открытые члены этого типа, объявленные как static (Shared в Visual Basic), являются потокобезопасными. Потокобезопасность членов экземпляров не гарантируется.


--
В космос. Судя по коду, он парсит текстовик и пилит это все в базу. Может bcp?
28 май 13, 15:56    [14360170]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
радикал радикалович
Guest
я хотел донести мысль - юли толку от такого "распараллеливания", не говоря уже о том, что поставщик класса SqlConnection не гарантирует корректной работы при использовании его в разных ОС threads.
28 май 13, 16:02    [14360219]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Lukich
Member

Откуда: Зелик
Сообщений: 275
радикал радикалович
я хотел донести мысль - юли толку от такого "распараллеливания", не говоря уже о том, что поставщик класса SqlConnection не гарантирует корректной работы при использовании его в разных ОС threads.

Спасибо! Parallel.ForEach дал прирост скорости раза в 2 (и все равно сервер работает "с прохладцей"), явно правильнее параллелить по разным коннектам, будем думать...и про bcp тоже))

Других рецетов не видится?
Может можно заставить сервер выполнять больше через 1 коннект?
28 май 13, 16:49    [14360654]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests  [new]
Glory
Member

Откуда:
Сообщений: 104751
Lukich
Может можно заставить сервер выполнять больше через 1 коннект?

В одном коннекте команды выполняются последовательно.
Чем быстрее будет выполнятся каждая команда, тем больше команд выполнится за единицу времени.
28 май 13, 16:51    [14360664]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
ЕвгенийВ
Member

Откуда: Москва
Сообщений: 4994
Нужно каждый раз создавать SQLConnection. Они все равно будут браться из пула и не будет счастие при работе с потоками и транзакциями.
28 май 13, 16:57    [14360715]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
ЕвгенийВ
Member

Откуда: Москва
Сообщений: 4994
*и будет счастие
28 май 13, 17:01    [14360747]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
ambarka_max
Member

Откуда: Россия
Сообщений: 517
Lukich
Может можно заставить сервер выполнять больше через 1 коннект?

Что мешает создать более 1 коннекта?
28 май 13, 17:17    [14360847]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Lukich
Member

Откуда: Зелик
Сообщений: 275
ЕвгенийВ
Нужно каждый раз создавать SQLConnection. Они все равно будут браться из пула и не будет счастие при работе с потоками и транзакциями.

В веб-приложении согласен, в консольном приложении к сожалению пула нет
28 май 13, 17:21    [14360883]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Гость333
Member

Откуда:
Сообщений: 3683
Lukich
в консольном приложении к сожалению пула нет

Как это нет?
28 май 13, 17:28    [14360927]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
ambarka_max
Member

Откуда: Россия
Сообщений: 517
Гость333
Lukich
в консольном приложении к сожалению пула нет

Как это нет?

Он невидимый
28 май 13, 17:33    [14360953]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Senja
Member

Откуда: Москва
Сообщений: 84
Попробуйте как-то так:
Parallel.ForEach(
    data, //коллекция с данными
    () =>
        {
            //Выполняется один раз для каждого потока в начале
                        
            SqlConnection conn = new SqlConnection(connstr);
            conn.Open();
            SqlTransaction tran = conn.BeginTransaction();
            SqlCommand cmd = new SqlCommand("....", conn, tran);
                        
            cmd.Parameters.Add("...", System.Data.SqlDbType.NVarChar, 100);
            //и т.д.

            return cmd;
        },
    (element, loopstate, cmd) =>
        {

            //Выполняется для каждого элемента
            cmd.Parameters[0].Value = element;
            cmd.ExecuteNonQuery();
            return cmd;
        },
    (cmd) =>
        {
            //Выполняется один раз для каждого потока в конце
            cmd.Transaction.Commit();
            cmd.Connection.Close();
        });
28 май 13, 17:47    [14361035]     Ответить | Цитировать Сообщить модератору
 Re: уперся по производительности в 2 тыс. Batch Requests / sec  [new]
Senja
Member

Откуда: Москва
Сообщений: 84
Но в любом случае, у вас каждая строка отправляется в базу отдельным батчем.
И каждый вызов cmd.ExecuteNonQuery добавляет Network Latency к общему времени.
По хорошему вам надо тем или иным способом собирать данные вместе и отправлять одним пакетом.
28 май 13, 17:52    [14361064]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Microsoft SQL Server Ответить