Тестирование параллелизма Azure SQL DW показывает, что внутри Azure не выполняются процедуры одновременно

Я прочитал 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)

  1. Я загрузил 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)
    )
    
  2. Я создал 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)
    )
    
  3. Я создал 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
    
  4. В 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 внутри компании.

Спасибо


person user2565762    schedule 22.09.2016    source источник


Ответы (1)


Хранилище данных SQL позволяет для одного запроса задействовать весь ЦП или ввод-вывод одним запросом. Когда запрос может полностью использовать ресурс, добавление другого запроса, который также конкурирует за тот же ресурс, будет означать, что оба будут работать медленнее. То есть, если у вас есть запрос, который использует 100% ЦП, и запускает другой запрос, который также использует 100% одновременно, оба запроса займут в два раза больше времени. Преимущество этого заключается в том, что один запрос будет выполняться как можно быстрее, а два запроса, конкурирующие за разные ресурсы, также будут выполняться как можно быстрее. Когда вы запускаете тест, подобный приведенному выше, где все запросы по существу идентичны, можно ожидать, что запуск тестов последовательно или одновременно займет одинаковое количество времени.

Чтобы дополнительно изучить свои результаты, вы можете найти статья о мониторинге полезна. В дополнение к просмотру sys.dm_pdw_exec_requests, попробуйте взглянуть на sys.dm_pdw_request_steps (время выполнения на этапе распределенного SQL), который, как я ожидал, будет учитывать большую часть 5 секунд, а также sys.dm_pdw_sql_requests (время выполнения по распределению ).

Кстати, выше вы упомянули, что не добавляли индекс columnstore для своего теста. В SQL DW файл тип таблицы по умолчанию - кластеризованный columnstore. Чтобы удалить этот индекс, измените предложение WITH следующим образом ...

С (РАСПРЕДЕЛЕНИЕ = HASH (ShortId), HEAP)

Надеюсь это поможет.

person Sonya Marshall    schedule 24.09.2016