Я прочитал Azure Concurrency и управление рабочими нагрузками в хранилище данных SQL https://azure.microsoft.com/en-us/documentation/articles/sql-data-warehouse-develop-concurrency/ и понять ограничения на количество одновременных запросов, которые можно использовать на основе в масштабе, но то, что я не могу понять и поэтому поднимаю здесь вопрос, заключается в том, что при тестировании того, что говорится в документе, я не могу получить результаты, которые утверждения Azure верны. Одновременное выполнение запросов по-прежнему занимает почти столько же времени, как и их последовательное выполнение.
Для примеров Вот тестовый пример (просто тест). У меня есть 5 хранимых процедур, выполнение которых по отдельности занимает около 1 секунды каждая. Поэтому, когда я запускаю все 5 последовательно, они занимают около 5 секунд, это ожидается, но когда я запускаю все 5 sprocs одновременно, я ожидал бы, что они завершатся чуть более чем за 1 секунду, но вместо этого они занимают около 4,5-4,7 секунды.
Может ли какой-нибудь эксперт по Azure объяснить, что может происходить?
Я думал, что это может быть конкуренция за ресурсы, но sys.dm_pdw_resource_waits не показывает блокировки во время работы 5 sprocs.
Когда я запускаю sys.dm_pdw_exec_requests, я вижу, что все 5 запросов exec sproc отправляются в течение нескольких мс. То же самое верно для Start_time и End_compile_time. end_time для всех 5 sprocs снова находится в пределах пары мс, но Total_elapsed_time ближе к 5000 мс вместо ожидаемых 1000 мс. Если я запускаю любой sproc отдельно, продолжительность составляет около 1000 мс. Это как если бы Concurrency запускал все 5 sproc одновременно, но внутри они выстраиваются в очередь и выполняются последовательно. Первоначально я тестировал DW200, у которого есть 8 слотов, которых должно хватить для моих 5 звездочек. На всякий случай я увеличил масштаб до DW1000, который позволяет мне выполнять до 32 одновременных запросов (я использую smallrc), но это не помогло решить эту проблему.
Вот как я это тестировал (используя DW1000)
Я загрузил 1000 записей в 5 отдельных таблиц stage (stage1, stage2 и т. Д.)
CREATE TABLE dbo.Stage1 ( ShortId bigint NOT NULL ,TestName varchar(50) NOT NULL ,TestValue varchar(50) NOT NULL ,CreateDate DateTime NOT NULL ) WITH ( DISTRIBUTION = HASH (ShortId) )
Я создал 5 таблиц фактов (fact1, fact2 и т. Д.), Каждая таблица имеет те же 4 столбца, что и stage, и распределяется с использованием хеша в первом столбце. Я не включил индекс columnstore (помните, что это всего лишь тест)
CREATE TABLE dbo.Fact1 ( ShortId bigint NOT NULL ,TestName varchar(50) NOT NULL ,TestValue varchar(50) NOT NULL ,CreateDate DateTime NOT NULL ) WITH ( DISTRIBUTION = HASH (ShortId) )
Я создал 5 хранимых процедур, которые вставляют данные в факты со сцены.
CREATE PROCEDURE dbo.TestLoad1 AS BEGIN INSERT INTO dbo.Fact1 --this is dbo.Fact2 in sproc 2 etc... SELECT stg.ShortId ,stg.PropertyName ,stg.PropertyValue ,stg.AcquistionTime FROM dbo.Stage1 stg WHERE stg.ShortId NOT IN (SELECT ShortId from dbo.Fact1) --Fact2 etc.. END
В C # я создал метод быстрого тестирования, который создает 5 соединений, команд и использует BeginExecuteReader / EndExecuteReader для выполнения sproc. (это всего лишь тест, так что простите за стиль / код)
SqlConnection cnn1 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False"); SqlConnection cnn2 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False"); SqlConnection cnn3 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False"); SqlConnection cnn4 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False"); SqlConnection cnn5 = new SqlConnection("Data Source=<server>;Initial Catalog=<database>;Persist Security Info = True;User ID =<username>;Password = <password>;Pooling = False;MultipleActiveResultSets = False;Connect Timeout = 30;Encrypt = True;TrustServerCertificate = False"); SqlCommand cmd1; SqlCommand cmd2; SqlCommand cmd3; SqlCommand cmd4; SqlCommand cmd5; IAsyncResult result1; IAsyncResult result2; IAsyncResult result3; IAsyncResult result4; IAsyncResult result5; SqlDataReader reader1; SqlDataReader reader2; SqlDataReader reader3; SqlDataReader reader4; SqlDataReader reader5; cnn1.Open(); cnn2.Open(); cnn3.Open(); cnn4.Open(); cnn5.Open(); cmd1 = new SqlCommand("dbo.TestLoad1", cnn1); cmd2 = new SqlCommand("dbo.TestLoad2", cnn2); cmd3 = new SqlCommand("dbo.TestLoad3", cnn3); cmd4 = new SqlCommand("dbo.TestLoad4", cnn4); cmd5 = new SqlCommand("dbo.TestLoad5", cnn5); cmd1.CommandType = CommandType.StoredProcedure; cmd2.CommandType = CommandType.StoredProcedure; cmd3.CommandType = CommandType.StoredProcedure; cmd4.CommandType = CommandType.StoredProcedure; cmd5.CommandType = CommandType.StoredProcedure; result1 = cmd1.BeginExecuteReader(CommandBehavior.SingleRow); result2 = cmd2.BeginExecuteReader(CommandBehavior.SingleRow); result3 = cmd3.BeginExecuteReader(CommandBehavior.SingleRow); result4 = cmd4.BeginExecuteReader(CommandBehavior.SingleRow); result5 = cmd5.BeginExecuteReader(CommandBehavior.SingleRow); reader1 = cmd1.EndExecuteReader(result1); //this is where the code waits for 5 seconds reader2 = cmd2.EndExecuteReader(result2); reader3 = cmd3.EndExecuteReader(result3); reader4 = cmd4.EndExecuteReader(result4); reader5 = cmd5.EndExecuteReader(result5); reader1.Close(); reader2.Close(); reader3.Close(); reader4.Close(); reader5.Close();
При отладке этого кода C # каждый оператор занимает ‹1 мс, пока я не дойду до строки reader1 = cmd1.EndExecuteReader (result1); Здесь он будет ждать 4-5 секунд, затем продолжит работу, и каждая следующая строка снова будет быстрой (‹1 мс).
Во время этой задержки, если я запускаю select * from sys.dm_pdw_exec_requests, я вижу, что все 5 запросов находятся в очереди и выполняются. Если я продолжу повторный запуск, продолжительность запроса будет продолжать увеличиваться, а затем внезапно (около 5 секунд) все 5 запросов скажут, что они выполнены.
Приветствуется любая помощь в объяснении того, что я делаю неправильно или что делает Azure SQL DW внутри компании.
Спасибо