it-swarm.asia

SQL: ما هو تباطؤ INSERTs إن لم يكن CPU أو IO؟

لدينا قاعدة بيانات لمنتج كثيف الكتابة. اشترينا للتو جهاز خادم جديد مع SSD للمساعدة. ولدهشتنا ، لم تكن عمليات الإدخال أسرع من تلك الموجودة على جهازنا القديم مع تخزين أبطأ بكثير. أثناء قياس الأداء لاحظنا أن معدل IO الذي أظهرته عملية SQL Server كان منخفضًا جدًا.

على سبيل المثال ، قمت بتشغيل البرنامج النصي الموجود على هذه الصفحة ، باستثناء أنني أضفت BEGIN TRAN و COMMIT حول الحلقة. في أحسن الأحوال ، كنت أرى أن استخدام القرص يصل إلى 7 ميجابايت/ثانية ، في حين أن وحدة المعالجة المركزية بالكاد لمست 5٪. تم تثبيت 64 جيجا بايت على الخادم ويستخدم 10. كان إجمالي وقت التشغيل دقيقتين و 15 ثانية للمكالمة الأولى إلى حوالي دقيقة واحدة للمكالمات اللاحقة. قاعدة البيانات على استعادة بسيطة وكانت خاملة أثناء الاختبار. أسقطت الجدول بين كل مكالمة.

لماذا هذا النص البسيط بطيء جدًا؟ بالكاد يتم استخدام الأجهزة على الإطلاق. تشير كل من أدوات قياس الأداء المخصصة للقرص و SQLIO إلى أن SSD يعمل بشكل صحيح بسرعات تصل إلى 500 ميجا بايت/ثانية لكل من القراءة والكتابة. أفهم أن عمليات الكتابة العشوائية أبطأ من عمليات الكتابة المتسلسلة ، لكنني أتوقع أن يكون إدراج بسيط مثل هذا ، إلى جدول بدون فهرسة مجمعة ، أسرع بكثير.

في نهاية المطاف ، السيناريو الخاص بنا أكثر تعقيدًا ، لكنني أشعر أنني بحاجة إلى فهم حالة بسيطة أولاً. باختصار ، يقوم تطبيقنا بحذف البيانات القديمة ، ثم يستخدم SqlBulkCopy لنسخ البيانات الجديدة إلى الجداول المرحلية ، وإجراء بعض التصفية ، وأخيرًا يستخدم MERGE و/أو INSERT INTO اعتمادًا على الحالات لنسخ البيانات إلى الجداول النهائية.

-> EDIT 1: اتبعت الإجراء المرتبط بـ Martin Smith ، وحصلت على النتيجة التالية:

[Wait Type]  [Wait Count] [Total Wait (ms)] [T. Resource Wait (ms)] [T. Signal Wait (ms)]
NETWORK_IO          5008              46735                 46587        148
LOGBUFFER           901               5994                  5977         17
PAGELATCH_UP        40                866                   865          1
SOS_SCHEDULER_YIELD 53279             219                   121          98
WRITELOG            5                 145                   145          0
PAGEIOLATCH_UP      4                 58                    58           0
LATCH_SH            5                 0                     0            0

أجد أنه من الغريب أن NETWORK_IO يستغرق معظم الوقت ، مع الأخذ في الاعتبار أنه لا توجد نتيجة للعرض ولا توجد بيانات لنقلها إلى أي مكان آخر بخلاف ملفات SQL. هل يشمل نوع NETWORK_IO جميع عمليات الإدخال/الإخراج؟

-> EDIT 2: لقد قمت بإنشاء قرص RAM بسعة 20 جيجابايت وقمت بتثبيت قاعدة بيانات من هناك. أفضل وقت قضيته على SSD هو 48 ثانية ، مع قرص RAM انخفض إلى 37 ثانية. NETWORK_IO لا يزال الانتظار الأكبر. كانت سرعة الكتابة القصوى للقرص RAM حوالي 250 ميجابايت/ثانية في حين أنها قادرة على تنفيذ عدة غيغابايت في الثانية. ما زالت لا تستخدم الكثير من وحدة المعالجة المركزية ، فما الذي يعيق SQL؟

20
Djof

أعلم أنه سؤال قديم ولكن قد لا يزال هذا يساعد الباحثين وهي مشكلة تظهر من حين لآخر.

السبب الرئيسي وراء وصولك إلى سقف الأداء دون أن ترى أي اختناق في الموارد هو أنك وصلت إلى حد ما يمكن معالجته في جلسة واحدة. لا تتم معالجة الحلقة بالتوازي ، ولكن يتم إجراء جميع الإدخالات بشكل تسلسلي.

في حالتي ، يستغرق الأمر 36 ثانية لإدراج 3 ملايين صف. وهذا يعني 36/30000000 = 0.000012 ثانية لكل صف. هذا سريع جدًا. على نظامي ، يستغرق الأمر ببساطة 0.000012 للذهاب عبر جميع الخطوات الضرورية.

الطريقة الوحيدة لإنجاز ذلك بشكل أسرع هي بدء جلسة ثانية بالتوازي.

إذا بدأت جلستين متوازيتين ، أقوم بعمل 15 مليون إدراج. كلاهما ينتهي في 18 ثانية. يمكنني زيادة حجمه ، ولكن إعداد الاختبار الحالي يصل إلى 95٪ من وحدة المعالجة المركزية بجلستين متوازيتين ، لذا فإن إجراء 3 سيؤدي إلى تحريف النتائج حيث أنني سأصل إلى عنق زجاجة وحدة المعالجة المركزية.

إذا بدأت جلستين متوازيتين بإدراج 3 ملايين صف ، فسينتهي كلاهما في 39 ثانية. أي أن 6 ملايين صف في 39 ثانية.

حسنًا ، لا يزال هذا يتركنا مع انتظار NETWORK_IO.

تتم إضافة انتظار NETWORK_IO من خلال حقيقة أنك تستخدم الأحداث الموسعة لتتبعها. في حالتي ، يستغرق الإدخال 36 ثانية (في المتوسط). عند استخدام طريقة الحدث الممتد (من الرابط أعلاه في التعليق الأول) هذا ما يتم تسجيله:

Wait Type             Wait Count  Total Wait Time (ms) Total Resource Wait Time (ms) Total Signal Wait Time (ms)
NETWORK_IO            3455        68808                68802                         6
PAGEIOLATCH_SH        3           64                   64                            0
PAGEIOLATCH_UP        12          58                   58                            0
WRITE_COMPLETION      8           15                   15                            0
WRITELOG              3           9                    9                             0
PAGELATCH_UP          2           4                    4                             0
SOS_SCHEDULER_YIELD   32277       1                    0                             1
IO_COMPLETION         8           0                    0                             0
LATCH_SH              3           0                    0                             0
LOGBUFFER             1           0                    0                             0

يمكنك أن ترى أن 68 ثانية من NETWORK_IO مسجلة. ولكن نظرًا لأن حلقة الإدراج عبارة عن إجراء مترابط واحد استغرق 36 ثانية ، فلا يمكن أن يكون ذلك. (نعم ، يتم استخدام سلاسل رسائل متعددة ، لكن العمليات متسلسلة ، ولا تكون متوازية أبدًا ، لذلك لا يمكنك حساب وقت انتظار أطول من إجمالي مدة الاستعلام)

إذا لم أستخدم الأحداث الممتدة ولكن فقط حالات انتظار DMVs في نسخة هادئة (مع تشغيل الإدراج فقط) أحصل على هذا:

Wait Type                   Wait Count  Total Wait Time (ms)  Total Resource Wait Time (ms) Signal Resource Wait Time (ms)
SOS_SCHEDULER_YIELD             8873                 0.21                                    0.01                                    0.20
PAGEIOLATCH_UP                  3                    0.02                                    0.02                                    0.00
PREEMPTIVE_OS_AUTHENTICATIONOPS 17                   0.02                                    0.02                                    0.00
PAGEIOLATCH_SH                  1                    0.00                                    0.00                                    0.00

لذا فإن NETWORK_IO التي كنت تراها في سجل الأحداث الموسعة ، لم تكن مرتبطة بحلقة الإدراج الخاصة بك. (إذا لم تقم بتشغيل nocount ، فسيكون لديك شبكة غير متزامنة ضخمة IO ينتظر ، +1 Martin)

ومع ذلك ، لا أعرف سبب ظهور NETWORK_IO في تتبع الأحداث الموسعة. تأكد من أن الكتابة إلى هدف ملف غير متزامن للأحداث يتراكم ASYNC_NETWORK_IO ، ولكن بالتأكيد يتم كل ذلك على SPID مختلف ثم الذي نقوم بالتصفية عليه. قد أسأل هذا السؤال الجديد بنفسي)

10
Edward Dortland

عادةً ما تبدأ بالنظر إلى sys.dm_exec_requests ، على وجه التحديد في wait_time ، wait_type و wait_resource لطلب (طلبات) INSERT الخاصة بك. سيعطي هذا إشارة واضحة إلى ما يمنع INSERT الخاص بك. ستشير النتائج إلى ما إذا كان التنافس على القفل ، وأحداث نمو الملف ، وانتظر تدفق السجل ، وتنافس التخصيص (يتجلى في تنافس مزلاج صفحة PFS) وما إلى ذلك وما إلى ذلك. بمجرد القياس ، قم بتحديث سؤالك وفقًا لذلك. أنا أحثك ​​بشدة على التوقف الآن وقراءة الانتظار وقوائم الانتظار منهجية استكشاف الأخطاء وإصلاحها قبل المتابعة.

9
Remus Rusanu

قمت بتشغيل البرنامج النصي للاختبار في الصفحة المرتبطة في OP مع BEGIN TRAN/COMMIT حول الحلقة. على الجهاز الخاص بي ، استغرق الأمر 1:28 لإكماله في المرة الأولى.

ثم قمت بنقل هذين الأمرين خارج الحلقة:

SELECT @Random = ROUND(((@Upper - @Lower -1) * Rand() + @Lower), 0)
SET @InsertDate = DATEADD(dd, @Random, GETDATE())

اكتمل في 28 ثانية بعد ذلك.

لا أعرف على وجه اليقين ما يحدث ، ولكن أعتقد أنه قد يكون هناك نوم من نوع ما في كود Rand() ربما كجزء من الخوارزمية التي يستخدمونها لتوليد الانتروبيا (عشوائي أفضل أعداد).

FWIW ، SSDs ليست دائما أفضل تقنية للتطبيقات الثقيلة الكتابة. للحصول على أفضل أداء ، تأكد من أن سجل قاعدة البيانات الخاص بك موجود على حرف محرك أقراص مختلف عن بيانات قاعدة البيانات ، وأن ملف السجل تم تطويره مسبقًا إلى أقصى حجم له ، ولا يتم قطع السجل أبدًا.

3
RickNZ

DMV آخر أستخدمه لتحديد البطء هو sys.dm_os_waiting_tasks . إذا كان استعلامك ليس كثيفًا في وحدة المعالجة المركزية ، فيمكنك العثور على مزيد من المعلومات حول الانتظار من DMV هذا.

1
StanleyJohns

أنا أتحقق من قائمة أحداث الانتظار لـ sql 2008 ولا أرى NETWORK_IO مدرجة: http://technet.Microsoft.com/en-us/library/ms179984 (v = sql.100). aspx

اعتقدت أن NETWORK_IO قد تم إدراجه للتو على أنه ASYNC_NETWORK_IO ، لذلك أردت أن أسأل ما إذا كان يمكنك التحقق من إصدار SQL الخاص بك مرة أخرى ، لأنني ببساطة أشعر بالفضول حول كيفية/لماذا يظهر حدث الانتظار لهذا الإصدار.

أما بالنسبة لانتظار الشبكة على الإطلاق ، نعم يمكن أن يحدث حتى إذا كنت تعمل على خادم مستقل. هل راجعت إعدادات بطاقات الشبكة الخاصة بك؟ أتساءل عما إذا كانت مشكلة.

في نهاية اليوم ، لا يوجد سوى عدد قليل من اختناقات الموارد الممكنة: الذاكرة ووحدة المعالجة المركزية وقرص الإدخال/الإخراج والشبكة والقفل. لقد أشرت إلى أن CPU و I/O ليسا المشكلة ، ولديك حدث انتظار NETWORK_IO ، لذا أقترح عليك إلقاء نظرة على تلك البطاقات NIC أولاً.

0
SQLRockstar