AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 28.01.2004, 15:29   #1  
online
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,689 / 1192 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
? Почему такое расхождение в скорости выполнения
Я не понимаю механизм доступа к данным в Axapta 2.5 Сделал простенький тест

PHP код:
static void Job_test(Args _args)
{
    
Connection      Con = new Connection();
    
Statement       Stmt Con.createStatement();
    
ResultSet       R;
    
CommaIo         fileOut;
    
int             timenowBegini;
    
InventTable     inventTable;

;

    
// Формирование ResultSet
    
fileOut = new CommaIo("C:\test_con.txt","W");
    
timenowBegin=timenow();
    
Stmt.executeQuery('SELECT TOP 1000 * FROM InventTable');

    while ( 
R.next() )
    {
        
fileOut.write(R.getString(1),
                        
R.getString(2),
                        
R.getString(3),
                        
R.getString(4),
                        
R.getString(5),
                        
R.getString(6),
                        
R.getString(7),
                        
R.getString(8),
                        
R.getString(9),
                        
R.getString(10),
                        
R.getString(11),
                        
R.getString(12),
                        
R.getString(13),
                        
R.getString(14),
                        
R.getString(15),
                        
R.getString(16),
                        
R.getString(17),
                        
R.getString(18),
                        
R.getString(19),
                        
R.getString(20) );
    }
    
info("Время сброса ResultSet = "+int2str(timenow()-timenowBegin));
    
Stmt.close();

    
// Чтение из табличной переменной
    
fileOut = new CommaIo("C:\test_sel.txt","W");
    
0;
    
timenowBegin=timenow();

    
select from inventTable;

    while (
i<=1000)
    {
        
i++;
        
next inventTable;
        
fileOut.write(inventTable.ItemGroupID,
                        
inventTable.ItemID,
                        
inventTable.ItemName,
                        
inventTable.ItemType,
                        
inventTable.PURCHMODEL,
                        
inventTable.HEIGHT,
                        
inventTable.WIDTH,
                        
inventTable.SALESMODEL,
                        
inventTable.COSTGROUPID,
                        
inventTable.REQGROUPID,
                        
inventTable.PRIMARYVENDORID,
                        
inventTable.NETWEIGHT,
                        
inventTable.DEPTH,
                        
inventTable.UNITVOLUME,
                        
inventTable.BOMUNITID,
                        
inventTable.DENSITY,
                        
inventTable.SCRAPTYPEID,
                        
inventTable.DIMENSION[1],
                        
inventTable.DIMENSION[2],
                        
inventTable.DIMENSION[3] );
    }
    
info("Время сброса прямого сканирования = "+int2str(timenow()-timenowBegin));

Получил расхождение в скорости примерно на порядок (если увеличить число выбрасываемых полей или количество строк это будет заметнее). Т.е. выброс в текстовый файл из ResulSet примерно на порядок МЕДЛЕННЕЕ, чем тот же выброс из табличной переменной. Почему собственно?

Собственно, изначально вопрос возник в попытке ускорить выброс результата выборки в текстовый файл. Выполнение Query с последующим циклом оказалось сопоставимо по времени с выбросом из ResulSet (примерно одинаково). Т.е. наиболее оптимальным по скорости оказалась такая технология:

-) Создать таблицу на сервере
-) Выполнить хранимую процедуру сервера по наполнению этой таблицы
-) Средствами Axapta сделать выброс из этой таблицы в текстовый файл

Но это достаточно сложно по исполнению, поэтому не хотелось бы этого делать.

Меня интересует, почему есть такое явное расхождение в скорости обработки казалось бы одинаковых операций?
Старый 28.01.2004, 15:51   #2  
andreynikolai is offline
andreynikolai
Участник
 
133 / 10 (1) +
Регистрация: 11.04.2002
А что здесь удивительного ?

При использовании класса UserConnection вы же фактически
напрямую обращаетесь к SQL-Server.

Ведь Аксапта - это же по сути скрипт.

Ваш код написанный на X++ должен пройти всю цепочку обработки бизнес-логики, компиляции,
преобразований прежде чем запрос уйдет к SQL-серверу.
Старый 28.01.2004, 15:57   #3  
online
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,689 / 1192 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Это Вы о чем?

Результат запроса я уже получил. Расхождение в скорости имеет место быть именно в цикле while. Т.е. это не собственно выполнение запроса, а выборка информации из результирующей выборки. Какое отношение ко всему этому имеет бизнес-логика и компиляция? Или компилируется каждая строка отдельно по мере исполнения?
Старый 28.01.2004, 16:10   #4  
macklakov is offline
macklakov
NavAx
Аватар для macklakov
 
2,230 / 975 (37) +++++++
Регистрация: 03.04.2002
Цитата:
Изначально опубликовано Владимир Максимов
уже получил
Не правда, select-ы стоят между timenow(). Скорее всего, ускорение достигается за счет кэширования, какая у вас конфигурация(2 или 3- tier) и настройки cacheLookup? Попробуй тот-же тест на более сложных запросах, по нескольким таблицам, результат должен отличаться в обратную сторону
P.S. next обычно ставят в конце while, т.к. select на автомате дает первую запись
Старый 28.01.2004, 16:30   #5  
online
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,689 / 1192 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Думаете - это первый вариант? Это упрощение моего оригинального запроса, где связаны 4 таблицы по INNER JOIN, да еще несколько промежуточных вычислений внутри цикла.

Я же писал, что тормозит именно цикл while. Все что вне него - это разовые операции принципиального влияния на общее время выполнения не оказывают

Хорошо, переставил timenowBegin = timenow() после select и R=... Перекинул next в конец цикла. На результат это никак не повлияло!

У меня 3-х звенка. Где здесь предмет кэширования я не понимаю. Точнее, если есть кэширование для табличной переменной, то почему его нет для ResultSet или Query?
Старый 28.01.2004, 16:54   #6  
france is offline
france
Участник
 
159 / 11 (1) +
Регистрация: 24.11.2003
Адрес: Москва
Может, дело в классе (методах класса) ResultSet?
Старый 28.01.2004, 17:06   #7  
online
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,689 / 1192 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Вообще-то, как я уже писал, я делал то же самое через QueryRun, т.е. цикл имел вид:

while (qr.next())
{
inventTable = qr.get(tablenum(InventTable));
fileOut.write(inventTable.ItemGroupID,inventTable.ItemID,...);
}

Скорость осталась примерно такая же как и при ResulSet. Т.е. явно медленнее, чем прямое сканирование табличной переменной. Конечно R.getString() влияет, только какое-то непонятное влияние.
Старый 28.01.2004, 17:36   #8  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Владимир Максимов, я совсем запутался.

Так кто на ком стоял? Какой метод быстрее, а какой медленнее?
Вы можете привести время для способа 1 и способа 2?
Старый 28.01.2004, 17:45   #9  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
ResultSet у него работает медленнее. С самого начала он так написал.
Я другого не понимаю: чего автор тут добивается? От гневных реплик кэширование, выполняемое ядром Аксапта в 2-уровневом ли, в 3-уровневом режимах для таблиц, явно описанных в AOT, в ResultSet не появится. И исходных кодов у нас нет, чтобы посмотреть, через сколько COM-компонентов и промежуточных интерфейсов работает ResultSet.
Старый 28.01.2004, 17:48   #10  
online
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,689 / 1192 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Самый быстрый способ - это сканирование таблицы, т.е.

while select inventTable ...

ну или как я написал в примере

select * from inventTable;
while (i<=1000) ...

Выбрасывает около 5тыс строк из 40 полей разного типа примерно за 5 секунд

Использование ResultSet или QueryRun на той же выборке дает время на порядок медленнее (примерно 50 секунд). Есть некоторое расхождение между использованием ResultSet и QueryRun, но в пределах погрешности (несколько секунд).

Вот я и пытаюсь понять: почему собственно? Подчеркну - кроме собственно commaIo.write() внутри цикла while ничего нет (ну, кроме QueryRun.get())
Старый 28.01.2004, 17:49   #11  
andreynikolai is offline
andreynikolai
Участник
 
133 / 10 (1) +
Регистрация: 11.04.2002
Скорее всего чтение из табличной переменной действительно быстрее потому что
resultSet табличной переменной кэширован.
А ResultSet полученный путем класса userConnection не кэшируется. Не
предусмотрено наверное.
Старый 28.01.2004, 18:04   #12  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Посмотрите в Profiler как обрабатываются ваши запросы SQL-сервером
Старый 28.01.2004, 18:09   #13  
online
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,689 / 1192 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Wamr
Может быть я чего-то не понимаю, но Вы хотите сказать, что на каждом шаге цикла, по команде next запрос SQL выполняется заново?
Время выполнения собственно запросов (на 5 тыс строк) на самом MS SQL 2000 составляет менее секунды
Старый 28.01.2004, 18:14   #14  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Изначально опубликовано andreynikolai
Скорее всего чтение из табличной переменной действительно быстрее потому что
resultSet табличной переменной кэширован.
Согласен. Если посмотреть на свойства таблицы inventTable, то увидим, что у нее установлено свойство CachLookup = Found.

select ... where этим свойством пользуется.
ResultSet вроде не пользуется.
Всегда считал, что query тоже этим свойством пользуется...

Владимир Максимов, скорость выполнения сравнивалась при первом после входа запуске или при повторных запусках? Что будет, если отключить кэширование, выйти, зайти и протестировать еще раз?
Старый 28.01.2004, 18:25   #15  
online
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,689 / 1192 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Видимо, я ненамеренно ввел в заблуждение тем, что использовал в примере таблицу InventTable. На самом деле, при проверке использовалась собственная таблица (в том смысле, что не основная) и у этой таблицы CachLookup = None (данные по времени приведены именно для такой настройки). Хотя использование InventTable не противоречит полученным результатам.

Результаты проверок от повторных запусков зависят слабо. Разница в пределах погрешности (несколько секунд). Сейчас убегаю, завтра продолжим
Старый 28.01.2004, 19:12   #16  
Wamr is offline
Wamr
----------------
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
 
1,737 / 858 (32) +++++++
Регистрация: 15.01.2002
Адрес: Москва
Записей в блоге: 7
Я знаю, что while select работает через курсоры и вытягивает записи с сервера (fetch) кусками по несколько записей. Как отрабатывает ResultSet я не знаю. Но раз уж вы заинтересовались этой темой, то было бы логично посмотреть именно работу SQL-сервера.
Так же было замечено, что ResultSet тормозит при определении конца цикла . Можно попробовать сделать top 110 а по счетчику оборвать цикл на 100 записях.
Старый 28.01.2004, 19:56   #17  
Vadik is offline
Vadik
Модератор
Аватар для Vadik
Лучший по профессии 2017
Лучший по профессии 2015
 
3,631 / 1849 (69) ++++++++
Регистрация: 18.11.2002
Адрес: гражданин Москвы
слушайте Wamr'a, Wamr плохого не посоветует

достаточно посмотреть на то, что попадает в профайлер в каждом проходе в первом цикле и что во втором

а) Connection, Statement
аксапта "честно" отправляет запрос "select top 1000 from myTable"
-exec sp_cursoropen ...
открывает курсор и фетчит записи ПО ОДНОЙ
-exec sp_cursorfetch 180150058, 2, 1, 1 - по одному вызову на запись
обратите внимание на последний параметр (1) и вот это

б) WHILE SELECT и табличная переменная
-exec sp_cursorexecute - у нас есть уже есть "откомпилированный" MSSQL запрос, так что мы его используем повторно. MSSQL не парсит его повторно, не строит план исполнения (он уже есть), это хорошо, что-то мы на этом сэкономили.
но все это фигня
-exec sp_cursorfetch 180150050, 2, 1, 16 - по одному вызову на несколько записей
обратите внимание на последний параметр, он равен 16 (у меня так с последней версией MDAC, сколько будет у вас - не знаю)
т.е. мы получаем recordset кусками по 16 записей
в конечном счете мы немного выиграли на суммарном траффике
но и это тоже фигня

мы сделали В РАЗЫ меньше fetch() по сравнению с первым вариантом

ну а раз время выполнение SELECT * FROM MYTABLE у нас мало по сравнению со временем на то, чтобы отослать результаты клиенту (запрос тривиальный), выигрыш у нас идет в разы, если не на порядок

а кэширование тут не при чем, SELECT * FROM MYTABLE, даже с условием WHERE, но не по уникальному ключу у нас не кэшируются, разве что с CacheLookup=EntireTable, но этот случай мы рассматривать не будем..

З.Ы. вот уж дорвался до форума так дорвался
З.З.Ы. до QueryRun не добрался, как-нибудь потом

подумалось.. насчет зависимости числа fetch-ащихся записей от версии MDAC я похоже того.. немного погорячился для одинаковых версий аксапты оно скорее всего будет одинаковым
Старый 28.01.2004, 20:00   #18  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Изначально опубликовано Vadik
а кэширование тут не при чем, SELECT * FROM MYTABLE, даже с условием WHERE, но не по уникальному ключу у нас не кэшируются
ок. спасибо.
Старый 29.01.2004, 10:38   #19  
online
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,689 / 1192 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Vadik
Как Вы получили эти числа в профайлере? У меня как я ни кручу профайлер ничего подобного не наблюдается (Axapta 2.5). В профайлере я вижу только дерево вызовов. Т.е. сколько времени на какую строку ушло.

Если судить по времени обработке строк, получается, что Statment фетчит по одной записи, а While Select по 24 за раз.

НО!

Если просуммировать время фетча для 24 строк Statmenta и сравнить с временем фетча для одной строки While Select, то я получаю примерно одинаковое значение.

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

Опять же, судя по плану выполнения запроса в профайлере индексы используются в обеих случаях. Точнее используется кластерный индекс. Собственно, этого и следовало ожидать. Здесь же идет голое сканирование строк в соответствии именно с кластерным индексом.

И еще, опять же судя по результатам профайлера, почему-то при выполнении Statment наблюдается повышенный обмен данными с сервером. У меня получились такие данные (только собственно цикл While):

Satment
Вызовов от клиента к серверу 0
Байт, от клиента к серверу 571969
Вызовов от сервера к клиенту 21001
Байт, от сервера к клиенту 1040040

While Select
Вызовов от клиента к серверу 0
Байт, от клиента к серверу 425451
Вызовов от сервера к клиенту 41
Байт, от сервера к клиенту 1435

Т.е. каким-то образом оптимизируется объем передаваемой информации. Единственная причина, которая приходит в голову - это информация о типах данных. О типах данных "родной" таблицы и так все известно, а вот о типах Satament - ничего не ясно. Хотя тут я не уверен.
Старый 29.01.2004, 18:57   #20  
Vadik is offline
Vadik
Модератор
Аватар для Vadik
Лучший по профессии 2017
Лучший по профессии 2015
 
3,631 / 1849 (69) ++++++++
Регистрация: 18.11.2002
Адрес: гражданин Москвы
Вообще-то я имел в виду профайлер от MSSQL, события
RPC:Completed
SQL:BatchCompleted
в нем все чудесно видно

по поводу использования индексов: речь вроде шла о кэшировании, при чем тут индексы?

По поводу траффика - ну да, по объему выигрыш около 25 процентов. Зато какая разница в количестве вызовов! Похоже, AOS и клиент тоже обмениваются пачками записей, а каждое обращение к Resultset, который живет на сервере - это лишний вызов, а на него тоже время требуется (и траффик). За счет этого и получается такой проигрыш

По мне, так Connection если и нужен, то для того, чтобы выполнить в нем что-то короткое типа exec myproc, truncate mytable. Работать с ним как-то по-другому - только лишний головняк
Теги
profiler, sql, полезное, производительность, профайлер

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Расхождение суммы проводки по поставщику и сопоставленной суммы petr DAX: Функционал 2 15.10.2008 23:31
Почему loka DAX: Программирование 2 01.12.2005 17:36
Ускорение выполнения запроса Oracle + MS Axapta Горбунов Дмитрий DAX: Программирование 17 15.11.2005 18:13
Профили выполнения проводки George V. Tavrizoff DAX: Функционал 8 07.09.2004 16:56
Можно ли проследить историю выполнения заказа? Hard DAX: Функционал 3 14.08.2003 10:06

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 16:01.
Powered by vBulletin® v3.8.5. Перевод: zCarot
Контактная информация, Реклама.