Здравствуйте, CyberRussia, Вы писали:
CR>Нужно железо для рабочей машины, где бы быстро (реально быстро и это важно) работала база данных MS SQL и многопоточное приложение из под net.core. CR>В настоящее время файл базы около 10Гб. В таблицах может быть до десятка миллионов записей. CR>На компе с i7 и HDD комплекс: приложение + база быстродействием базы упирается в HDD и обработка задачи занимает 3.5 часа. Учитывая, что это еще не самая сложная задача... CR>В общем хочется понять, насколько для MS SQL является более приоритетным диск или процессор.
При таком соотношении чисел возникает зверски сильное ощущение, что быстродействие упирается в неоптимальность приложения и приоритетным является программист. Конечно, вопрос, что за расчёты... но блин, пять лет назад у меня на рабочей станции биллинг со всеми завихрениями на порядок быстрее считался, включая radius-сервер. А вот что может быть неоптимально в приложении... да очень много что... с бедра:
— чрезмерная многопоточность
— чрезмерное дробление операций
— вытаскивание из БД и расчёт в приложении того, что куда быстрее посчитать в базе
— многократное таскание из БД в приложение одних и тех же данных
— избыток операций, требующих синхронизации (например, слишком частые коммиты)
— реконнект на каждую запись
— и т. д.
Здравствуйте, CyberRussia, Вы писали: CR>Ускорить в комплексе. Затык вызывает диск. Однако непонятно, если условно заменить HDD на SSD, будет ли продолжать утыкаться в диск или в процессор. Понятно, что точный ответ может дать только практика. Но интересует опыт людей, что оказывалось в железе наиболее "узким".
Практически всегда диск. Или память. Которой не хватает для кеширования из-за чего всё опять упирается в диск.
PS Попробуй ограничить количество чтений из бд. Вообще все, что можно, перенеси в бд, благо mssql уже лет 15 позволяет писать функции на .net.
Всё, что нас не убивает, ещё горько об этом пожалеет.
Здравствуйте, CyberRussia, Вы писали:
CR>На каждую запись из таблицы source_1 делаются запросы в таблицы source_2 ... source_6 по пяти полям (результат до 100 записей из каждой, сами таблицы содержат до десятков миллионов записей каждая). Производится расчет, результаты сохраняются в три таблицы destination_2 ... destination_4 (аналогично select -> update or insert).
Sounds like RBAR... Row by agonizing row...
Я очень похожее оптимизировал — source -> complex transformation -> several destinations.
Время рассчета сократилось с нескольких дней до нескольких минут после перевода логики на работу с наборами данных, а не с перебором построчным.
Железо тут мало поможет, ИМХО. Тебе надо логику переписывать на работу с наборами данных, а не с отдельными записями.
CR>В общем хочется понять, насколько для MS SQL является более приоритетным диск или процессор. Достаточно ли SSD или нужно более хитрое решение.
Так нужно ваше приложение + mssql ускорить, или mssql?
Если первое, то что мешает посмотреть использование CPU,
памяти и диска за эти 3.5 часа и выяснить что именно вызывает "затык"?
Здравствуйте, CyberRussia, Вы писали:
CR>Но интересует опыт людей, что оказывалось в железе наиболее "узким".
У тебя всего 10ГБ база при 16 гигах оперативки. Почему она с диска у тебя много читает и что именно она читает?
Сама фраза "упирается в диск" мало что говорит, если честно.
Узкие места — память обычно. Которая вызывает затыки на диске и ЦПУ.
Вот если просто так, от балды советовать по фотографии — увеличь объем памяти и поставь SSD.
Скорее всего, поможет, но насколько поможет — я не знаю.
Может у тебя там 3.5 часа из-за RBAR подхода и надо код переписывать, а не железо апгрейдить, например.
Здравствуйте, CyberRussia, Вы писали:
CR>Есть таблица, назовем ее source_1...
Это паттерн "запросы в цикле". Или, как сказал Softwarer,
— вытаскивание из БД и расчёт в приложении того, что куда быстрее посчитать в базе
— многократное таскание из БД в приложение одних и тех же данных
Если все необходимые для расчетов данные находятся в таблицах (не дергаются веб-сервисы и т.п.) и алгоритмы расчета не суперсложные и не CPU-bound, расчет можно перенести в базу (в хранимые процедуры) и ускорить примерно на порядок.
Здравствуйте, CyberRussia, Вы писали:
CR>Станет ли проект когда-либо бизнесом — я без понятия. Вообще, по ТЗ складывается ощущение, что это лично-индивидуальный заказ человека. Заказчик не хочет нанимать кого-то еще и предлагает разбираться мне. Зато готов купить железо.
1) Покупаете железо (SSD и память) и договариваетесь с компанией-продавцом, что возможно потребуется все купленное вернуть и money-back.
2) Установив новое железо, поводите эксперименты с засеканием времени — чтобы определить: повлиял ли upgrade на ситуацию?
3) Если не повлиял — смотрите код (и возможно — возвращаете железо продавцам).
CR>И, да, я НЕ являюсь спецом по БД.
Ну, теперь возможно станете и спецом по БД.
P.S. Если позволяет материнка — берите SSD NVMe (они работают быстрее, нежели SSD SATA).
Здравствуйте, CyberRussia, Вы писали:
W>>Проблема в том, что без изучения твоей конкретной ситуации все советы это "пальцем в небо". Советую нанять специалиста и оплатить его услуги. CR>Совет конечно хороший, только экономически нецелесообразных.
То есть проблема не настолько серьезная, что из-за нее бизнес деньги теряет или клиентов и т.п. OK. Тогда можно пока не париться. Или не спеша разобраться в проблеме и самому стать специалистом.
Здравствуйте, CyberRussia, Вы писали:
V>>А используются? CR>Эм... озадачили... А, разве, могут иметься, но не использоваться? CR>Индексы проставлены на пять полей по которым выбираются записи.
То есть, там нет джойнов, а просто выборка из одной таблицы по условию равенства пяти полей?
Если так и по этим полям есть индекс, то с вероятностью 99% он используется, удостовериться можно, посмотрев план выполнения запроса.
Еси условие более сложное или есть джойны — то могут быть нюансы. В любом случае, execution plan поможет в расследовании.
Здравствуйте, Ромашка, Вы писали:
Р>Пропробуй изменить уровень изоляции. Или поставить read uncommited, или snapshot.
Ты сразу говори, что uncommitted только лишь для быстрой проверки, а не как фикс.
Здравствуйте, CyberRussia, Вы писали:
CR>Нужно железо для рабочей машины, где бы быстро (реально быстро и это важно) работала база данных MS SQL и многопоточное приложение из под net.core.
Идешь в магазин и покупаеш.
CR>В настоящее время файл базы около 10Гб. В таблицах может быть до десятка миллионов записей.
Это ничтожно мало, у нас средняя база 10Тб.
CR>На компе с i7 и HDD комплекс: приложение + база быстродействием базы упирается в HDD и обработка задачи занимает 3.5 часа. Учитывая, что это еще не самая сложная задача...
У тебя не с железом проблема а с логикой в приложении.
CR>В общем хочется понять, насколько для MS SQL является более приоритетным диск или процессор. Достаточно ли SSD или нужно более хитрое решение.
10Гб целиком в памяти поместиться. Все должно летать.
CR>P.S. Приложение хотя и одно, но многопоточное и стучится в базу одновременно множеством соединений.
1000 фунтов в час и за неделю я найду причину твоей проблемы. А может и за пол часа.. тут как повезет. И может даже решу ее.
Здравствуйте, CyberRussia, Вы писали:
CR>Да, совершенно верно. Я могу запустить трассировку. Посмотреть какие запросы де факто посылает приложение. Сколько они занимают времени. Но понять по совокупности множества коротких запросов причину медленной работы я не могу. Так что — да, я еще не научился анализировать работы БД и пользоваться для этого соответствующими инструментами.
я тебе написал в самом начале, а воз и ныне там.. Я тебе уже и так и сяк помоч хочу, но ты ведь уперся как баран и не читаешь.. Если у тебя есть лишние 5-6 лет то я тебя не тороплю. Примерно через это время ты придешь к этому:
..список из 100 самых длительных запросов (по общему времени исполнения) с цифрами сколько времени в среднем занимает одно выполнение, максимальное время выполнения, среднее и максимальное кол-во чтений из базы данных за одно выполнение, количество выполнений в единицу времени.
Ну а там останется немного — исправить найденые запросы. Это еще года 3-4 с такими темпами..
Нужно железо для рабочей машины, где бы быстро (реально быстро и это важно) работала база данных MS SQL и многопоточное приложение из под net.core.
В настоящее время файл базы около 10Гб. В таблицах может быть до десятка миллионов записей.
На компе с i7 и HDD комплекс: приложение + база быстродействием базы упирается в HDD и обработка задачи занимает 3.5 часа. Учитывая, что это еще не самая сложная задача...
В общем хочется понять, насколько для MS SQL является более приоритетным диск или процессор. Достаточно ли SSD или нужно более хитрое решение.
P.S. Приложение хотя и одно, но многопоточное и стучится в базу одновременно множеством соединений.
Здравствуйте, CyberRussia, Вы писали:
CR>Нужно железо для рабочей машины, где бы быстро (реально быстро и это важно) работала база данных MS SQL и многопоточное приложение из под net.core. CR>В настоящее время файл базы около 10Гб. В таблицах может быть до десятка миллионов записей.
Вообще ни о чем.
CR>На компе с i7 и HDD комплекс: приложение + база быстродействием базы упирается в HDD и обработка задачи занимает 3.5 часа. Учитывая, что это еще не самая сложная задача...
Индексы правильно настроены?
CR>В общем хочется понять, насколько для MS SQL является более приоритетным диск или процессор. Достаточно ли SSD или нужно более хитрое решение. CR>P.S. Приложение хотя и одно, но многопоточное и стучится в базу одновременно множеством соединений.
Сколько памяти стоит? Если жестко упирается в диск, подумать о разнесении базы на несколько дисков (SSD) для паралельного доступа.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
AJD>Вообще ни о чем.
Угу. Мне так все говорят. И отдельно взятые запросы выполняются быстро.
AJD>Индексы правильно настроены?
Насколько моего знания БД хватает, а я в них не специалист — да.
Грубо говоря — прочитать полмиллиона записей, на каждую сделать расчет и сохранить в другую таблицу. Плюс на каждую запись сделать примерно по пять запросов в другие таблицы (примерно по 100 записей), по каждой из которых сделать расчет и сохранить в соответствующие таблицы.
AJD>Сколько памяти стоит? Если жестко упирается в диск, подумать о разнесении базы на несколько дисков (SSD) для паралельного доступа.
16Гб. Может и стоит, вот и спрашиваю какое железо смотреть. В идеале с указанием на конкретные марки / модели.
Здравствуйте, Zhendos, Вы писали: Z>Так нужно ваше приложение + mssql ускорить, или mssql? Z>Если первое, то что мешает посмотреть использование CPU, Z>памяти и диска за эти 3.5 часа и выяснить что именно вызывает "затык"?
Ускорить в комплексе. Затык вызывает диск. Однако непонятно, если условно заменить HDD на SSD, будет ли продолжать утыкаться в диск или в процессор. Понятно, что точный ответ может дать только практика. Но интересует опыт людей, что оказывалось в железе наиболее "узким".
Нужно установить любой SSD и оперативной памяти хотя бы 64-128 ГБ. Процессор желательно тоже побыстрей, i7 ничего не говорит. Если железо десктопное, то сейчас нормальный вариант это 10900K или похожий Xeon.
Здравствуйте, Softwarer, Вы писали:
S>Здравствуйте, CyberRussia, Вы писали:
CR>>Нужно железо для рабочей машины, где бы быстро (реально быстро и это важно) работала база данных MS SQL и многопоточное приложение из под net.core. CR>>В настоящее время файл базы около 10Гб. В таблицах может быть до десятка миллионов записей. CR>>На компе с i7 и HDD комплекс: приложение + база быстродействием базы упирается в HDD и обработка задачи занимает 3.5 часа. Учитывая, что это еще не самая сложная задача... CR>>В общем хочется понять, насколько для MS SQL является более приоритетным диск или процессор.
S>При таком соотношении чисел возникает зверски сильное ощущение, что быстродействие упирается в неоптимальность приложения и приоритетным является программист.
Вполне возможно, в БД не силен
S>- чрезмерная многопоточность
ThreadPool в который грузится не более 12 задач (по числу процессорных потоков)
S>- чрезмерное дробление операций
Если имеется в виду возможность выполнения одной sql команды вместо группы команд — нет
S>- вытаскивание из БД и расчёт в приложении того, что куда быстрее посчитать в базе
Вот это возможно
S>- многократное таскание из БД в приложение одних и тех же данных
Нет
S>- избыток операций, требующих синхронизации (например, слишком частые коммиты)
На каждый завершенный блок бизнес логики
S>- реконнект на каждую запись
Нет
Здравствуйте, CyberRussia, Вы писали:
CR>На компе с i7 и HDD комплекс: приложение + база быстродействием базы упирается в HDD и обработка задачи занимает 3.5 часа. Учитывая, что это еще не самая сложная задача...
Если чисто для скоросьти — разнесите базу на несколько дисков. Таблицы пусть лежать на SSD (NVME, не SATA), а логи — либо на отдельном SSD либо рейде из нескольких HDD.
CR>В общем хочется понять, насколько для MS SQL является более приоритетным диск или процессор. Достаточно ли SSD или нужно более хитрое решение.
Зависит от нагрузки, нужно профилировать. Измерьте, чего у вас не хватает? пропускной способности диска или латентности.
И насколько параллельные запросы размазаны по таблицам: обрабатывают их подряд или в случайном порядке.
Ну и, как уже советовали, проверьте, что соединения используют индексы. Если нет — то начать нужно именно с них.
W>Проблема в том, что без изучения твоей конкретной ситуации все советы это "пальцем в небо". Советую нанять специалиста и оплатить его услуги.
Совет конечно хороший, только экономически нецелесообразных.
V>И насколько параллельные запросы размазаны по таблицам: обрабатывают их подряд или в случайном порядке.
Подряд
V>Ну и, как уже советовали, проверьте, что соединения используют индексы. Если нет — то начать нужно именно с них.
Индексы имеются
W>То есть проблема не настолько серьезная, что из-за нее бизнес деньги теряет или клиентов и т.п. OK. Тогда можно пока не париться. Или не спеша разобраться в проблеме и самому стать специалистом.
Станет ли проект когда-либо бизнесом — я без понятия. Вообще, по ТЗ складывается ощущение, что это лично-индивидуальный заказ человека. Заказчик не хочет нанимать кого-то еще и предлагает разбираться мне. Зато готов купить железо. Если я буду нанимать за свои, то учитывая стоимость консультаций действительно хорошего специалиста, то мне выгоднее будет от проекта просто отказаться.
И, да, я НЕ являюсь спецом по БД. И то, что столкнусь с такой проблемой на этапе ознакомления с ТЗ не представлял.
Здравствуйте, CyberRussia, Вы писали:
V>>Ну и, как уже советовали, проверьте, что соединения используют индексы. Если нет — то начать нужно именно с них. CR>Индексы имеются
А используются?
V>То есть, там нет джойнов, а просто выборка из одной таблицы по условию равенства пяти полей?
Есть таблица, назовем ее source_1 с примерно полумиллионом данных. Несколько потоков приложения запрашивают из нее с условием по одному полю (в совокупности работы потоков будет запрошена данные из всей таблицы, без повторных запросов отдельных записей).
На каждую запись поток приложения производит расчет. Затем делает запрос в таблицу, назовем destination_1, по уже пяти полям на наличие ранее созданной записи. Да — update, нет — insert. На каждую запись из таблицы source_1 делаются запросы в таблицы source_2 ... source_6 по пяти полям (результат до 100 записей из каждой, сами таблицы содержат до десятков миллионов записей каждая). Производится расчет, результаты сохраняются в три таблицы destination_2 ... destination_4 (аналогично select -> update or insert).
Создать первичный и вторичные ключи ДО этого вычисления невозможно, потому что данные получены из сторонних разных источников. И их нужно сопоставить друг с другом и привести к виду необходимому для последующей работы оператора.
V>Если так и по этим полям есть индекс, то с вероятностью 99% он используется, удостовериться можно, посмотрев план выполнения запроса.
Посмотрел — используется
Здравствуйте, CyberRussia, Вы писали:
V>>То есть, там нет джойнов, а просто выборка из одной таблицы по условию равенства пяти полей? CR>Есть таблица, назовем ее source_1 с примерно полумиллионом данных. Несколько потоков приложения запрашивают из нее с условием по одному полю (в совокупности работы потоков будет запрошена данные из всей таблицы, без повторных запросов отдельных записей). CR>На каждую запись поток приложения производит расчет. Затем делает запрос в таблицу, назовем destination_1, по уже пяти полям на наличие ранее созданной записи. Да — update, нет — insert. На каждую запись из таблицы source_1 делаются запросы в таблицы source_2 ... source_6 по пяти полям (результат до 100 записей из каждой, сами таблицы содержат до десятков миллионов записей каждая). Производится расчет, результаты сохраняются в три таблицы destination_2 ... destination_4 (аналогично select -> update or insert). CR>Создать первичный и вторичные ключи ДО этого вычисления невозможно, потому что данные получены из сторонних разных источников. И их нужно сопоставить друг с другом и привести к виду необходимому для последующей работы оператора.
Если при таком сценарии тормозит именно база, то, скорее всего, сам расчёт очень быстрый.
Тогда можно улучшить ситуацию читая не по одной записи, а блоками, скажем, по 100 штук, обрабатывать их и записывать пачками.
Вот это: "делаются запросы в таблицы source_2 ... source_6 по пяти полям (результат до 100 записей из каждой..." не совсем понятно:
Это пять таблиц source_2 ... source_6, одно ключевое поле в каждой или это одна та таблица destination_1 с ключём из пяти полей?
Саму вставку в целевые таблицы source_2 ... source_6 вы делаете по одной записи (один запрос на одну запись)?
Если да, и если в обновляемом результате по 100 строк, то можно все 100 строк заносить одним запросом, это существенно ускорит.
V>Если при таком сценарии тормозит именно база, то, скорее всего, сам расчёт очень быстрый. V>Тогда можно улучшить ситуацию читая не по одной записи, а блоками, скажем, по 100 штук, обрабатывать их и записывать пачками.
Открыт reader и в нем перебираются записи
V>Вот это: "делаются запросы в таблицы source_2 ... source_6 по пяти полям (результат до 100 записей из каждой..." не совсем понятно: V>Это пять таблиц source_2 ... source_6, одно ключевое поле в каждой или это одна та таблица destination_1 с ключём из пяти полей?
Ключ из пяти полей
V>Саму вставку в целевые таблицы source_2 ... source_6 вы делаете по одной записи (один запрос на одну запись)?
Да
V>Если да, и если в обновляемом результате по 100 строк, то можно все 100 строк заносить одним запросом, это существенно ускорит.
И если одна из 100 строк почему-то не сохранится, то транзакция откатит все 100.
V>>Если да, и если в обновляемом результате по 100 строк, то можно все 100 строк заносить одним запросом, это существенно ускорит. CR>И если одна из 100 строк почему-то не сохранится, то транзакция откатит все 100.
Ну и шут с ним, повторите всю транзакцию, она, видимо не сильно большая. Вероятность-то такого расклада невелика. Зато скорость записи на порядок вырастет.
Р>ты в одном потоке не пробовал запускать? сильно время выполнения отличается?
Процентов 30 многопоточность дает прироста. В одной потоке на загрузку компа как-то не посмотрел, только когда увидел, что многопоточность на дала "вау" эффекта.
P.S. А что не так с reader'ом? В каждом потоке свой, перебирают разные записи таблицы
Здравствуйте, CyberRussia, Вы писали: CR>Процентов 30 многопоточность дает прироста.
Пропробуй изменить уровень изоляции. Или поставить read uncommited, или snapshot.
CR>P.S. А что не так с reader'ом? В каждом потоке свой, перебирают разные записи таблицы
Блокировки. Извини, из твоих пояснений ничего не понятно, например, делается ли вставка в source_2...source6 — тут
она появляется. Поэтому для начала read uncommited везде и посмотреть, изменится ли время. Если существенно улучшится — будем думать в этом направлении дальше.
Всё, что нас не убивает, ещё горько об этом пожалеет.
Р>Пропробуй изменить уровень изоляции. Или поставить read uncommited, или snapshot.
Полностью прогнать на uncommited не было возможности. По частичной оценки, можно предположить, что общее время сократиться минут на 20.
Р>Блокировки. Извини, из твоих пояснений ничего не понятно, например, делается ли вставка в source_2...source6
Нет, в source ничего не вставляется. Оттуда только читается. Вставляется в destination, либо insert, либо update
СR>1000 фунтов в час и за неделю я найду причину твоей проблемы. А может и за пол часа.. тут как повезет. И может даже решу ее.
Заплатить овердофига за то, чтобы через неделю человек сказал: "не, не решу проблему"... нефиговый бизнес-план
Здравствуйте, CyberRussia, Вы писали:
CR>Заплатить овердофига ..
Я тебя не заставляю, хочешь есть кактус ешь его! Ты хоть трейс с базы снять догодался?
CR>..чтобы через неделю человек сказал: "не, не решу проблему"... нефиговый бизнес-план
Если проблема с базой то я гарнтирую что ее решу, если проблема с тем что ты в приложении что то "накрутил" я только могу констатировать факт этого и подсказать где копать.
СR>Я тебя не заставляю, хочешь есть кактус ешь его!
А как я еще буду совершенствоваться, если не разбираться с проблемами?
СR>Ты хоть трейс с базы снять догодался?
Что такое "трейс"? Ты хоть по английски термины пиши. Я же в БД только основы знаю.
СR>Если проблема с базой то я гарнтирую что ее решу, если проблема с тем что ты в приложении что то "накрутил" я только могу констатировать факт этого и подсказать где копать.
Понятно. В любом случае если я начну доставать из своего кармана, то мне будет экономически выгоднее от проекта отказаться. А кого-то еще нанимать заказчик не хочет, говорит — сам разбирайся.
Здравствуйте, CyberRussia, Вы писали:
CR>А как я еще буду совершенствоваться, если не разбираться с проблемами?
Так разбирайся, 5-6 лет тебе хватит если ты специалиста не хочешь нанимать.. У специалиста то опыта лет 15-20 будет а у тебя 0.
CR>Что такое "трейс"? Ты хоть по английски термины пиши. Я же в БД только основы знаю.
Я не знаю как оно по русски, это вообще-то английски термин. Уверен что ты знаешь основы?
How to use SQL Profiler to create a SQL trace in Microsoft SQL Server
CR>Понятно. В любом случае если я начну доставать из своего кармана, то мне будет экономически выгоднее от проекта отказаться. А кого-то еще нанимать заказчик не хочет, говорит — сам разбирайся.
Я бы на месте заказчика нанял другого исполнителя. Лично против тебя ничего не имею, просто констатирую факт. У меня больше 10 лет опыта внедрения проэктов в международных компаниях.
СR>Так разбирайся, 5-6 лет тебе хватит если ты специалиста не хочешь нанимать.. У специалиста то опыта лет 15-20 будет а у тебя 0.
Так я завтра на пенсию и не собираюсь. Какие-то пять лет на то, чтобы разобраться в работе баз данных. Да без проблем. А потом не буду дурацкие вопросы на форуме задавать.
СR>Я не знаю как оно по русски, это вообще-то английски термин. Уверен что ты знаешь основы?
Ну, так и пиши — trace. Я уж думал ты действительно, что-то сложное имел в виду используя специфический жаргон разработчиков БД. Конечно делал, как вообще можно что-то отлаживать без трассировки.
СR>Я бы на месте заказчика нанял другого исполнителя. Лично против тебя ничего не имею, просто констатирую факт. У меня больше 10 лет опыта внедрения проэктов в международных компаниях.
Вот видимо потому что ты работаешь с международными компаниями и привык бюджеты проектов считать миллионами долларов, ты себе плохо представляешь какие бывают заказчики и с каким бюджетом, из малого бизнеса или вообще индивидуалы.
Здравствуйте, CyberRussia, Вы писали:
CR>Так я завтра на пенсию и не собираюсь. Какие-то пять лет на то, чтобы разобраться в работе баз данных. Да без проблем. А потом не буду дурацкие вопросы на форуме задавать.
Ну тогда удачи тебе!
CR>Ну, так и пиши — trace. Я уж думал ты действительно, что-то сложное имел в виду используя специфический жаргон разработчиков БД. Конечно делал, как вообще можно что-то отлаживать без трассировки.
И чего нашел? Можно список из 100 самых длительных запросов (по общему времени исполнения) с цифрами сколько времени в среднем занимает одно выполнение, максимальное время выполнения, среднее и максимальное кол-во чтений из базы данных за одно выполнение, количество выполнений в единицу времени.
Я к тому что, если бы ты это сделал твой вопрос на этом форуме выглядел бы подругому. Но факт в том что ты этого не сделал.
Здравствуйте, Свободу rg45, Вы писали: СR>И чего нашел? Можно список из 100 самых длительных запросов (по общему времени исполнения) с цифрами сколько времени в среднем занимает одно выполнение, максимальное время выполнения, среднее и максимальное кол-во чтений из базы данных за одно выполнение, количество выполнений в единицу времени. СR>Я к тому что, если бы ты это сделал твой вопрос на этом форуме выглядел бы подругому. Но факт в том что ты этого не сделал.
Факт в том, что когда я смотрю на отсутствие длительных запросов (по сравнению с остальными), то понимаю, что не понимаю как интерпретировать результат. Когда (до этого) видел длительные, то хотя бы примерно было понятно куда копать и что делать. А вот сейчас уже сказалось мое отсутствие знаний в области анализа БД. Говорю же — у меня только базовые знания, create table, select left join, create index
Ты, видимо в силу большого опыта, забываешь, что воспользоваться инструментом и понять его результат не одно и то же.
И нет, проблему я не нашел, иначе бы и вопроса не было. Это уже в ответ на вопрос мне тут доходчиво объяснили что и как я сделал неправильно.
Здравствуйте, CyberRussia, Вы писали:
CR>..воспользоваться инструментом и понять его результат не одно и то же.
Умерть пользоваться инструментом = понять результат работы. Если ты рукояткой молотка забиваешь гвозди означает ли это что ты можешь пользоватья молотком? Так что факт в том что ты не умеешь пользоваться профайлером.
CR>И нет, проблему я не нашел, иначе бы и вопроса не было. Это уже в ответ на вопрос мне тут доходчиво объяснили что и как я сделал неправильно.
Прочитай мое предидушее сообщение, там четко написано что мы от тебя ожидаем что бы хоть как то понять причины твоих бед. Если ты не можешь предоставить эту информацию, то и советы тут будут переключись в анкоммитед (фары протри)..
СR>Умерть пользоваться инструментом = понять результат работы. Если ты рукояткой молотка забиваешь гвозди означает ли это что ты можешь пользоватья молотком? Так что факт в том что ты не умеешь пользоваться профайлером.
Да, совершенно верно. Я могу запустить трассировку. Посмотреть какие запросы де факто посылает приложение. Сколько они занимают времени. Но понять по совокупности множества коротких запросов причину медленной работы я не могу. Так что — да, я еще не научился анализировать работы БД и пользоваться для этого соответствующими инструментами.
CR>>И нет, проблему я не нашел, иначе бы и вопроса не было. Это уже в ответ на вопрос мне тут доходчиво объяснили что и как я сделал неправильно. СR>Прочитай мое предидушее сообщение, там четко написано что мы от тебя ожидаем что бы хоть как то понять причины твоих бед. Если ты не можешь предоставить эту информацию, то и советы тут будут переключись в анкоммитед (фары протри)..
Не знаю, кто эти "мы" за которых ты говоришь. Мне уже объяснили, где я налажал и я объяснение понял. Еще не исправил, поэтому сравнить глубину своей ошибки в числах пока не могу.
Здравствуйте, CyberRussia, Вы писали:
CR>..Зато готов купить железо..
Если база размером в несколько гигабайт не работает на i7 с 32Гб памяти и SSD то она врядли быстрее заработает на сервере. Ну либо нужно будет сервер с 40 процессорами. Не думаю что он готов это счастье оплатить..
Ты пойми железо увеличивает производительность линейно. А тюнинг твоих запросов по экспаненте.
CR>И, да, я НЕ являюсь спецом по БД. И то, что столкнусь с такой проблемой на этапе ознакомления с ТЗ не представлял.
Ну ты накодил такой продукт. Собери трейс найди тот запрос который слишком часто или слишком медленно работает и вуаля, проблема почти решена. Можно еще посмотреть каких индексов не хватает и добавить. Если не нанимаеш специалиста, то хоть книжки какие почитай по тюненгу баз данных, глядиш придет просветление.
Переписал в хранимую процедуру и попытался с перебора записей перейти на пакетную обработку
Хранимка
ALTER PROCEDURE CalculateTicker
@Ticker nvarchar(10)
AS
BEGIN
SET NOCOUNT ON;
declare @result int;
insert into [akkumulator] ([ticker], [dimenstion], [year], [quarterly], [datequarterly])
select DISTINCT q.[ticker], 'ARQ', year(q.[reportperiod]), (month(q.[reportperiod])-1) / 3 + 1, min(q.[reportperiod])
from [vw_quarterly] q
where q.[ticker] = @Ticker and q.[reportperiod] is not null
group by q.[ticker], year(q.[reportperiod]), (month(q.[reportperiod])-1) / 3 + 1;
-- на один квартал может приходиться несколько записей, но работаем только с однойselect @result = @@ROWCOUNT;
with rev_group_3q (revdev, netinc, netincdev, tangiblesdev, ticker, reportperiod)
as
(
select iif(count(qsum.[revenue]) != 0 and SUM(qsum.[revenue]) != 0,
qmain.[revenue] / (cast(SUM(qsum.[revenue]) as decimal(20,3)) / count(qsum.[revenue])),
null) as revdev
, iif(count(qsum.[netincmn]) != 0,
(cast(SUM(qsum.[netincmn]) as decimal(20,3)) / count(qsum.[netincmn])),
null) as netinc
, iif(count(qsum.[netincmn]) != 0 and SUM(qsum.[netincmn]) != 0,
qmain.[netincmn] / (cast(SUM(qsum.[netincmn]) as decimal(20,3)) / count(qsum.[netincmn])),
null) as netincdev
, iif(count(qsum.[tangibles]) != 0 and SUM(qsum.[tangibles]) != 0,
qmain.[tangibles] / (cast(SUM(qsum.[tangibles]) as decimal(20,3)) / count(qsum.[tangibles])),
null) as netincdev
, qsum.[ticker]
, qmain.[reportperiod]
from [vw_quarterly] qsum
inner join [vw_quarterly] qmain
on qsum.[ticker] =qmain.[ticker]
and qsum.dimension = [qmain].[dimension]
where qsum.[reportperiod] >= dateadd(MONTH, -9, qmain.[reportperiod]) -- агрегирование за 9 месяцевand qsum.[reportperiod] < qmain.[reportperiod]
group by qsum.[ticker],qmain.[reportperiod],qmain.[revenue],qmain.[netincmn],qmain.[tangibles]
),
rev_group_4q (revdev, netinc, netincdev, tangiblesdev, ticker, reportperiod)
as
(
select iif(count(qsum.[revenue]) != 0 and SUM(qsum.[revenue]) != 0,
qmain.[revenue] / (cast(SUM(qsum.[revenue]) as decimal(20,3)) / count(qsum.[revenue])),
null) as revdev
, iif(count(qsum.[netincmn]) != 0,
(cast(SUM(qsum.[netincmn]) as decimal(20,3)) / count(qsum.[netincmn])),
null) as netinc
, iif(count(qsum.[netincmn]) != 0 and SUM(qsum.[netincmn]) != 0,
qmain.[netincmn] / (cast(SUM(qsum.[netincmn]) as decimal(20,3)) / count(qsum.[netincmn])),
null) as netincdev
, iif(count(qsum.[tangibles]) != 0 and SUM(qsum.[tangibles]) != 0,
qmain.[tangibles] / (cast(SUM(qsum.[tangibles]) as decimal(20,3)) / count(qsum.[tangibles])),
null) as netincdev
, qsum.[ticker]
, qmain.[reportperiod]
from [vw_quarterly] qsum
inner join [vw_quarterly] qmain
on qsum.[ticker] =qmain.[ticker]
and qsum.dimension = [qmain].[dimension]
where qsum.[reportperiod] >= dateadd(MONTH, -12, qmain.[reportperiod]) -- агрегирование за 12 месяцевand qsum.[reportperiod] < qmain.[reportperiod]
group by qsum.[ticker],qmain.[reportperiod],qmain.[revenue],qmain.[netincmn],qmain.[tangibles]
),
rev_group_8q (revdev, netinc, netincdev, tangiblesdev, ticker, reportperiod)
as
(
select iif(count(qsum.[revenue]) != 0 and SUM(qsum.[revenue]) != 0,
qmain.[revenue] / (cast(SUM(qsum.[revenue]) as decimal(20,3)) / count(qsum.[revenue])),
null) as revdev
, iif(count(qsum.[netincmn]) != 0,
(cast(SUM(qsum.[netincmn]) as decimal(20,3)) / count(qsum.[netincmn])),
null) as netinc
, iif(count(qsum.[netincmn]) != 0 and SUM(qsum.[netincmn]) != 0,
qmain.[netincmn] / (cast(SUM(qsum.[netincmn]) as decimal(20,3)) / count(qsum.[netincmn])),
null) as netincdev
, iif(count(qsum.[tangibles]) != 0 and SUM(qsum.[tangibles]) != 0,
qmain.[tangibles] / (cast(SUM(qsum.[tangibles]) as decimal(20,3)) / count(qsum.[tangibles])),
null) as netincdev
, qsum.[ticker]
, qmain.[reportperiod]
from [vw_quarterly] qsum
inner join [vw_quarterly] qmain
on qsum.[ticker] =qmain.[ticker]
and qsum.dimension = [qmain].[dimension]
where qsum.[reportperiod] >= dateadd(MONTH, -24, qmain.[reportperiod]) -- агрегирование за 24 месяцаand qsum.[reportperiod] < qmain.[reportperiod]
group by qsum.[ticker],qmain.[reportperiod],qmain.[revenue],qmain.[netincmn],qmain.[tangibles]
)
update [akkumulator]
set [revenue] = q.[revenue] * .000001,
[netincomecommon] = [netincmn] * .000001,
[netincome] = q.[netinc] * .000001,
[tangiblebookvalue] = [tangibles] * .000001,
[ordinarysharesnumber] = [sharesbas] * .000001,
[datereport] = [datekey],
[p] = [sharesbas] * .000001 / [close],
[pe] = [sharesbas] / [close] / q.netinc,
[revenue_3q] = rev_group_3q.[revdev],
[netinccom_3q] = rev_group_3q.netinc,
[netinccomdev_3q] = rev_group_3q.netincdev,
[tan_3q] = rev_group_3q.tangiblesdev,
[revenue_4q] = rev_group_4q.[revdev],
[netinccom_4q] = rev_group_4q.netinc,
[netinccomdev_4q] = rev_group_4q.netincdev,
[tan_4q] = rev_group_4q.tangiblesdev,
[revenue_8q] = rev_group_8q.[revdev],
[netinccom_8q] = rev_group_8q.netinc,
[netinccomdev_8q] = rev_group_8q.netincdev,
[tan_8q] = rev_group_8q.tangiblesdev
from [akkumulator] a
inner join [vw_quarterly] q on a.[ticker] = q.[ticker] and a.[datequarterly] = q.[reportperiod]
inner join rev_group_3q on rev_group_3q.[ticker] = q.[ticker] and rev_group_3q.[reportperiod] = q.[reportperiod]
inner join rev_group_4q on rev_group_4q.[ticker] = q.[ticker] and rev_group_4q.[reportperiod] = q.[reportperiod]
inner join rev_group_8q on rev_group_8q.[ticker] = q.[ticker] and rev_group_8q.[reportperiod] = q.[reportperiod]
left join [ya_historydata] h on q.[ticker] = h.[ticker] and convert(date, h.[date]) = convert(date, q.[datekey])
where q.[ticker] = @Ticker and q.[reportperiod] is not null
insert into [akkreport]
([ticker], [dimenstion], [quarterly],[year],[date],[close],[delta])
select DISTINCT [ya_historydata].[ticker],
'ARQ',
[akkumulator].[quarterly],
[akkumulator].[year],
[ya_historydata].[date],
[ya_historydata].[close],
hc.[close] / [ya_historydata].[close]
from [ya_historydata] inner join [akkumulator]
on [ya_historydata].[ticker] = [akkumulator].[ticker] and ([ya_historydata].[date] >= DATEADD(day,-100, [akkumulator].[datereport]) and [ya_historydata].[date] <= DATEADD(day,100,[akkumulator].[datereport]))
inner join [ya_historydata] hc
on hc.ticker = [akkumulator].ticker and cast(hc.[date] as date) = cast([akkumulator].[datereport] as date)
where [akkumulator].[ticker] = @Ticker and [ya_historydata].[close] is not null and [ya_historydata].[close] != 0
return @result
END
GO
Строго говоря процедура недописана. Должно быть еще три агрегирования по годам.
set statistics time on
DECLARE @return_value int
EXEC @return_value = [dbo].[CalculateTicker]
@Ticker = N'AMZN'
SELECT 'Return Value' = @return_value
GO
set statistics time off
SQL Server parse and compile time:
CPU time = 235 ms, elapsed time = 241 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 15 ms, elapsed time = 46 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 235 ms, elapsed time = 494 ms.
SQL Server Execution Times:
CPU time = 11859 ms, elapsed time = 11877 ms.
SQL Server parse and compile time:
CPU time = 7 ms, elapsed time = 7 ms.
SQL Server Execution Times:
CPU time = 109 ms, elapsed time = 345 ms.
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server Execution Times:
CPU time = 12469 ms, elapsed time = 13013 ms.
(1 row affected)
SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 0 ms.
SQL Server parse and compile time:
CPU time = 0 ms, elapsed time = 0 ms.
Процедуру планировалось использовать для запуска с примерно 15 000 различных входных параметров.
vw_quarterly — вьюха объединяющая две таблицы и использующая where для дополнительного условия
таблица из которой берет вьюха первичный ключ по комбинации ticker, dimenstion, calendardate
индексы по ticker + datekey + dimenstion
ya_historydata — первичный ключ по комбинации ticker и date
reportperiod + ticker + dimenstion
netinccmn
netinc
akkumulator — первичный ключ по комбинации ticker, dimenstion, quarterly, year
идексы по ticker, year, quarterly — три отдельных
Здравствуйте, CyberRussia, Вы писали:
CR>Переписал в хранимую процедуру и попытался с перебора записей перейти на пакетную обработку CR>... CR>Процедуру планировалось использовать для запуска с примерно 15 000 различных входных параметров.
Смысл пакетной обработки в том, чтобы выполнять расчет сразу для всех входных параметров. Записать их в таблицу и присоединять ее в ваших запросах.
W>Смысл пакетной обработки в том, чтобы выполнять расчет сразу для всех входных параметров. Записать их в таблицу и присоединять ее в ваших запросах.
Так оно, конечно, но:
1. В текущей реализации хранимой процедуры общее время больше, чем когда обсчет велся на стороне приложения с прохождением по записям
2. Полная обработка сразу всех записей не позволяет в окне приложения отображать ход процесса
И план выполнения запросы.
CR>идексы по ticker, year, quarterly — три отдельных
И какие из них используются?
Еше бы неплохо было схему БД видеть и трейс.
dateadd(MONTH, -9, qmain.[reportperiod])
Вот из за этого у тебя индексы скорее всего и не используются. Сделай тогда уже персистед колумн и на него индекс. Но без плана и схемы БД трудно сказать шо пошло не так.
СR>И план выполнения запросы. СR>Еше бы неплохо было схему БД видеть и трейс.
В файле план выполнения и трейс. Вроде правильно собрал. http://files.rsdn.org/57699/proc.zip
Связей между таблицами — нет. Исходные таблицы для расчетов, это данные полученные из разных сторонних источников. На момент получения у них нет идентификаторов. Взаимную целостность они не обеспечивают. Данные в результирующей таблице akkumulator нет смысла привязывать к исходным данным, потому что в этом нет логического смысла, кроме того, уже в самое ближайшее время планируется получать данные и из других внешних источников обработанный результат сохраняя все в той же akkumulator. По хорошему должен быть вторичный ключ в akkreport от akkumulator , но де факто его нет.
CR>>идексы по ticker, year, quarterly — три отдельных
СR>И какие из них используются?
Судя по плану выполнения процедуры, она их не использует
СR>
СR>dateadd(MONTH, -9, qmain.[reportperiod])
СR>Вот из за этого у тебя индексы скорее всего и не используются. Сделай тогда уже персистед колумн и на него индекс.
Понял, спасибо