Производительность: как SQL Server обрабатывает параллельные запросы из нескольких соединений из одного настольного приложения .NET - PullRequest
3 голосов
/ 22 мая 2009

Описание однопоточной версии:

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

  • Модуль скоринга выполняет ряд (только для чтения) запросов к базе данных.
  • Последовательная обработка, соединение с одной базой данных.

Я решил создать многопоточность вышеописанной программы, разделив список вопросов на куски и создав поток для каждого.

Каждый поток открывает свое соединение с базой данных и работает со своим списком вопросов (около 95 вопросов в каждом из 6 потоков). Приложение ожидает завершения всех потоков, затем агрегирует результаты для отображения.

К моему удивлению, многопоточная версия работала примерно в то же время, занимая около 17 секунд вместо 17.

Вопросы:

Почему я не вижу такого увеличения производительности, которого я ожидаю от одновременного выполнения запросов в отдельных потоках с отдельными подключениями? Машина имеет 8 процессоров.

Будет ли SQL Server обрабатывать запросы одновременно, когда они поступают из одного приложения, или он (или сам .net) сериализует их?

Может ли быть что-то неправильно настроено, что заставит его работать быстрее, или я просто подталкиваю SQL Server к его вычислительным пределам?

Текущая конфигурация:

Microsoft SQL Server Developer Edition 9.0.1406 RTM
ОС: Windows Server 2003 Standard
Процессоры: 8
Оперативная память: 4 ГБ

Ответы [ 6 ]

3 голосов
/ 22 мая 2009

Это просто выстрел в темноте, но я уверен, что вы не видите повышения производительности, потому что они сериализуются в базе данных из-за блокировки общих ресурсов (записей). Теперь для мелкого шрифта.

Я предполагаю, что ваш код C # действительно правильный, и вы фактически запускаете отдельные потоки и запускаете каждый запрос параллельно. Без обид, но я видел много таких заявлений, и код по сути был последовательным в клиенте по разным причинам. Вы должны проверить это, наблюдая за сервером (через Profiler или используя sys.dm_exec_requests и sys.dm_exec_sessions).

Также я предполагаю, что ваши запросы имеют одинаковый вес. у вас нет одного потока, который длится 15 секунд, а 5 - 100 мс.

Симптомы, которые вы описываете, в отсутствие подробностей, указывают на то, что у вас есть операция записи в начале каждого потока, которая берет X-блокировку на каком-либо ресурсе. Первый поток запускается и блокирует ресурс, остальные 5 ждут. Первый поток завершен, освобождает ресурс, затем следующий захватывает его, остальные 4 ждут. Таким образом, последний поток должен дождаться выполнения всех остальных 5. Это было бы очень легко устранить, посмотрев на sys.dm_exec_requests и проследив, что блокирует запросы.

Кстати, вы должны рассмотреть возможность использования Asynchronous Processing = true и полагаться на асинхронные методы, такие как BeginExecuteReader, чтобы запускать команды при выполнении параллельно без накладных расходов потоков на стороне клиента.

0 голосов
/ 14 ноября 2009

Вы можете просто проверить диспетчер задач, когда процесс запущен. Если он показывает загрузку процессора на 100%, то его привязка к процессору. В противном случае его IO Bound.

Для гиперпоточности загрузка процессора на 50% примерно равна загрузке на 100%!

Ух ты, я не понял, сколько лет было этой нити. Я думаю, это всегда хорошо, чтобы оставить отзыв для других глядя.

0 голосов
/ 27 мая 2009

Я выполнил запрос на соединение для sys.dm_os_workers, sys.dm_os_tasks и sys.dm_exec_requests для task_address, и вот результаты (некоторые неинтересные / нулевые поля исключены, другие с префиксом ex или os для разрешения неоднозначностей):

-COL_NAME-  -Thread_1-  -Thread_2-  -Thread_3-  -Thread_4-

task_state  SUSPENDED   SUSPENDED   SUSPENDED   SUSPENDED
context_switches_count  2   2   2   2
worker_address  0x3F87A0E8  0x5993E0E8  0x496C00E8  0x366FA0E8
is_in_polling_io_completion_routine 0   0   0   0
pending_io_count    0   0   0   0
pending_io_byte_count   0   0   0   0
pending_io_byte_average 0   0   0   0
wait_started_ms_ticks   1926478171  1926478187  1926478171  1926478187
wait_resumed_ms_ticks   1926478171  1926478187  1926478171  1926478187
task_bound_ms_ticks 1926478171  1926478171  1926478156  1926478171
worker_created_ms_ticks 1926137937  1923739218  1921736640  1926137890
locale  1033    1033    1033    1033
affinity    1   4   8   32
state   SUSPENDED   SUSPENDED   SUSPENDED   SUSPENDED
start_quantum   3074730327955210    3074730349757920    3074730321989030    3074730355017750
end_quantum 3074730334339210    3074730356141920    3074730328373030    3074730361401750
quantum_used    6725    11177   11336   6284
max_quantum 4   15  5   20
boost_count 999 999 999 999
tasks_processed_count   765 1939    1424    314
os.task_address 0x006E8A78  0x00AF12E8  0x00B84C58  0x00D2CB68
memory_object_address   0x3F87A040  0x5993E040  0x496C0040  0x366FA040
thread_address  0x7FF08E38  0x7FF8CE38  0x7FF0FE38  0x7FF92E38
signal_worker_address   0x4D7DC0E8  0x571360E8  0x2F8560E8  0x4A9B40E8
scheduler_address   0x006EC040  0x00AF4040  0x00B88040  0x00E40040
os.request_id   0   0   0   0
start_time  2009-05-26 19:39    39:43.2 39:43.2 39:43.2
ex.status   suspended   suspended   suspended   suspended
command SELECT  SELECT  SELECT  SELECT
sql_handle  0x020000009355F1004BDC90A51664F9174D245A966E276C61  0x020000009355F1004D8095D234D39F77117E1BBBF8108B26  0x020000009355F100FC902C84A97133874FBE4CA6614C80E5  0x020000009355F100FC902C84A97133874FBE4CA6614C80E5
statement_start_offset  94  94  94  94
statement_end_offset    -1  -1  -1  -1
plan_handle 0x060007009355F100B821C414000000000000000000000000  0x060007009355F100B8811331000000000000000000000000  0x060007009355F100B801B259000000000000000000000000  0x060007009355F100B801B259000000000000000000000000
database_id 7   7   7   7
user_id 1   1   1   1
connection_id   BABF5455-409B-4F4C-9BA5-B53B35B11062    A2BBCACF-D227-466A-AB08-6EBB56F34FF2    D330EDFE-D49B-4148-B7C5-8D26FE276D30    649F0EC5-CB97-4B37-8D4E-85761847B403
blocking_session_id 0   0   0   0
wait_type   CXPACKET    CXPACKET    CXPACKET    CXPACKET
wait_time   46  31  46  31
ex.last_wait_type   CXPACKET    CXPACKET    CXPACKET    CXPACKET
wait_resource               
open_transaction_count  0   0   0   0
open_resultset_count    1   1   1   1
transaction_id  3052202 3052211 3052196 3052216
context_info    0x  0x  0x  0x
percent_complete    0   0   0   0
estimated_completion_time   0   0   0   0
cpu_time    0   0   0   0
total_elapsed_time  54  41  65  39
reads   0   0   0   0
writes  0   0   0   0
logical_reads   78745   123090  78672   111966
text_size   2147483647  2147483647  2147483647  2147483647
arithabort  0   0   0   0
transaction_isolation_level 2   2   2   2
lock_timeout    -1  -1  -1  -1
deadlock_priority   0   0   0   0
row_count   6   0   1   1
prev_error  0   0   0   0
nest_level  2   2   2   2
granted_query_memory    512 512 512 512

Предсказатель плана запроса для всех запросов показывает пару узлов, 0% для выбора и 100% для поиска в кластеризованном индексе.

Редактировать: поля и значения, которые я пропустил, где (то же самое для всех 4 потоков, кроме context_switch_count): exec_context_id(0), host_address(0x00000000), status(0), is_preemptive(0), is_fiber(0), is_sick(0), is_in_cc_exception(0), is_fatal_exception(0), is_inside_catch(0), context_switch_count(3-89078), exception_num(0), exception_Severity(0), exception_address(0x00000000), return_code(0), fiber_address(NULL), language(us_english), date_format(mdy), date_first(7), quoted_identifier(1), ansi_defaults(0), ansi_warnings(1), ansi_padding(1), ansi_nulls(1), concat_null_yields_null(1), executing_managed_code(0)

0 голосов
/ 22 мая 2009

возможно ли, что потоки разделяют соединение? Вы проверили, что несколько SPID создаются при запуске (sp_who)?

0 голосов
/ 22 мая 2009

Я склоняюсь к тому, что вы пытаетесь решить проблему ввода-вывода с потоками, которая почти никогда не работает. IO - IO, и больше потоков не увеличивает трубу. Вам лучше загрузить все вопросы и ответы на них в одном пакете и обрабатывать пакет локально, используя несколько потоков.

Сказав это, вы, вероятно, испытываете некоторую блокировку дБ, которая вызывает медлительность. Поскольку вы говорите о запросах только для чтения, попробуйте использовать подсказку with (nolock) в своих запросах, чтобы посмотреть, поможет ли это.

Что касается обработки SQL-сервера, то, насколько я понимаю, SQL Server будет пытаться обрабатывать столько соединений одновременно, сколько возможно (по одному оператору за раз), вплоть до максимального количества соединений, разрешенного конфигурацией. Тип проблемы, с которой вы сталкиваетесь, почти никогда не является проблемой потока и почти всегда является проблемой блокировки или ввода-вывода.

0 голосов
/ 22 мая 2009

Насколько велика ваша база данных? Насколько быстры ваши HDD / Raid / Другое хранилище

Возможно, ваша БД связана с вводом / выводом?

...