سؤال

مرحبًا، لدي مؤشر في الإجراء المخزن ضمن SQL Server 2000 (لا يمكن التحديث الآن) الذي يقوم بتحديث الجدول بالكامل ولكن عادةً ما يستغرق اكتماله بضع دقائق.ولست بحاجة لجعله أسرع.فيما يلي جدول المثال الذي تمت تصفيته بواسطة معرف منتج عشوائي؛جدول المثال http://img231.imageshack.us/img231/9464/75187992.jpgحيث أن GDEPO: مستودع الدخول، CDEPO: مستودع الخروج، Adet:الكمية، كمية E_CIKAN المستخدمة.

سجل التوضيحات:
1:20 وحدة تدخل المستودع 01 ، 2:10 أوراق وحدة 01.3:5 وحدة أوراق 01 (E_CIKAN للتسجيل الأول سيكون 15 الآن) 4:10 وحدات أخرى تدخل المستودع 01.5:3 وحدة تترك 01 من السجل الأول.لاحظ الآن أن السجل الأول قد تم تعيين E_CIKAN على 18.6:وهنا تأتي المشكلة:3 وحدة تحتاج إلى مغادرة المستودع 01.يستغرق الأمر وحدتين من السجل الأول ووحدة واحدة من السجل الخامس.يمكن لـ SP الخاص بي التعامل مع هذا الأمر بشكل جيد كما هو موضح في الصورة، إلا أنه بطيء حقًا.

إليك الإجراء المخزن المترجم إلى اللغة الإنجليزية؛

CREATE PROC [dbo].[UpdateProductDetails]
as
UPDATE PRODUCTDETAILS SET E_CIKAN=0;
DECLARE @ID int
DECLARE @SK varchar(50),@DP varchar(50)  --SK = STOKKODU = PRODUCTID, DP = DEPOT
DECLARE @DEMAND float     --Demand=Quantity, We'll decrease it record by record
DECLARE @SUBID int
DECLARE @SUBQTY float,@SUBCK float,@REMAINS float
DECLARE SH CURSOR FAST_FORWARD FOR
SELECT [ID],PRODUCTID,QTY,EXITDEPOT FROM PRODUCTDETAILS  WHERE (EXITDEPOT IS NOT NULL) ORDER BY [DATE] ASC
OPEN SH
FETCH NEXT FROM SH INTO @ID, @SK,@DEMAND,@DP

WHILE (@@FETCH_STATUS = 0)
BEGIN
   DECLARE SA CURSOR FAST_FORWARD FOR
   SELECT [ID],QTY,E_CIKAN FROM PRODUCTDETAILS  WHERE (QTY>E_CIKAN) AND (PRODUCTID=@SK) AND (ENTRYDEPOT=@DP) ORDER BY [DATE] ASC
   OPEN SA
   FETCH NEXT FROM SA INTO @SUBID, @SUBQTY,@SUBCK
   WHILE (@@FETCH_STATUS = 0) AND (@DEMAND>0)
   BEGIN
      SET @REMAINS=@SUBQTY-@SUBCK
      IF @DEMAND>@REMAINS  --current record isnt sufficient, use it and move on
      BEGIN
         UPDATE PRODUCTDETAILS SET E_CIKAN=QTY WHERE ID=@SUBID;
         SET @DEMAND=@DEMAND-@REMAINS
      END
      ELSE
      BEGIN
         UPDATE PRODUCTDETAILS SET E_CIKAN=E_CIKAN+@DEMAND WHERE ID=@SUBID;
         SET @DEMAND=0
      END
      FETCH NEXT FROM SA INTO @SUBID, @SUBAD,@SUBCK
   END
   CLOSE SA
   DEALLOCATE SA
   FETCH NEXT FROM SH INTO @ID, @SK,@DEMAND,@DP
END
CLOSE SH
DEALLOCATE SH
هل كانت مفيدة؟

المحلول

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

لديك مؤشرين متداخلين:

  • الأول هو تحديد كل صف يحتوي على مستودع خروج محدد.يأخذ المنتج والمستودع والمبلغ، ثم:
  • تعمل حلقة المؤشر الداخلية عبر الصفوف الخاصة بهذا المنتج/المستودع الذي تم تحديد مستودع الإدخال فيه.ويضيف إلى E_CIKAN لكل واحد، حتى يتم تخصيص كل المنتج.

لذلك يتم تشغيل حلقة المؤشر الداخلية مرة واحدة على الأقل لكل صف من مستودعات الخروج لديك.ومع ذلك، فإن نظامك لا يهتم حقًا بالعناصر التي تم إرسالها مع أي معاملة - فأنت تحاول فقط حساب قيم E_CIKAN النهائية.

لذا ...

تحتاج الحلقة الخارجية الخاصة بك فقط إلى الحصول على المجموع كمية العناصر المشحونة لكل مجموعة منتج/مستودع.ومن ثم يمكنك تغيير تعريف المؤشر الخارجي إلى:

DECLARE SH CURSOR FAST_FORWARD FOR
    SELECT PRODUCTID,EXITDEPOT, Sum(Qty) as TOTALQTY
    FROM PRODUCTDETAILS  
    WHERE (EXITDEPOT IS NOT NULL) 
    GROUP BY PRODUCTID, EXITDEPOT
OPEN SH
FETCH NEXT FROM SH INTO @SK,@DP,@DEMAND

(ثم ​​قم أيضًا بتغيير FETCH المطابق من SH في نهاية الكود للمطابقة بوضوح)

هذا يعني أن مؤشرك الخارجي سيحتوي على عدد أقل من الصفوف التي سيمر عبرها، وسيحتوي مؤشرك الداخلي تقريبًا على نفس المقدار من الصفوف التي سيمر عبرها.

لذلك ينبغي أن يكون هذا أسرع.

نصائح أخرى

يجب أن تكون المؤشرات هي الحل الأسوأ أداءً لأي مشكلة عند استخدام T-SQL.

لديك خياران اعتمادًا على تعقيد ما تحاول تحقيقه حقًا:

  1. محاولة إعادة كتابة مجموعة الكود بأكملها لاستخدام عمليات تعيين. ستكون هذه أسرع طريقة أداء ... ولكن في بعض الأحيان لا يمكنك القيام بذلك باستخدام عمليات تعيين.

  2. استبدل المؤشر بمجموعة من متغير الجدول (مع عمود الهوية) ، ومكافحة ، وأثناء الحلقة. يمكنك بعد ذلك حلقة من خلال كل صف من متغير الجدول. أداء أفضل من المؤشر ... على الرغم من أنه قد لا يبدو كما لو كان.

قم بإزالة المؤشر وإجراء تحديثات الدُفعة. لا يزال يتعين عليّ العثور على تحديث لا يمكن القيام به في دفعة.

قم بإزالة المؤشر وأعد كتابة ذلك كتحديث من الانضمام في استعلام المؤشر ، يمكنك جعل IFS حالة إذا كنت بحاجة إلى ذلك. أنا مشغول جدًا اليوم لأكتب التحديث لك اليوم ...

أولاً ، إذا كان يجب عليك استخدام المؤشر ، وقمت بتحديث الأشياء ، ثم أعلنت المؤشر مع جملة For Update. (انظر المثال أدناه. لاحظ أن المثال لا يعتمد على الكود الخاص بك على الإطلاق.)

بعد قولي هذا ، هناك عدد لا يحصى من الطرق لاستخدام شيء آخر غير المؤشرات ، وغالبًا ما تستفيد من الجداول المؤقتة. أود التحقيق في هذا الطريق بدلاً من المؤشرات.

DECLARE LoopingCursor CURSOR LOCAL DYNAMIC
FOR
    select sortorder from customfielddefinition
    where context=@targetContext
FOR UPDATE OF sortorder

أستطيع أن أرى أن المشكلة التي تحاول حلها معقدة للغاية:

  • عندما يكون هناك صف مع GDEPO محدد ، فإنه يمثل المخزون الذهاب إلى DEPO ، وتريد استخدام E_CIKAN من هذا الصف لتتبع مقدار ما يتم استخدامه في وقت لاحق. ستبدأ E_Cikan من 0 ثم يتم إضافتها إلى الأسهم ، حتى تصل إلى ADET.

  • لذلك عندما يكون هناك صف لاحق مع تحديد CDEPO ، فإنه يعيد تشغيل الأسهم ، وتريد العودة إلى E_cikan من GDEPO-Row وتعديل E_Cikan ، عن طريق إضافة كمية المخزون إليها.

  • عندما يكون هناك صفين منفصلان مع دخول الأسهم (محدد GDEPO) ، يكون هناك في بعض الأحيان تدفقًا فائلاً عندما يصل E_cikan من صف واحد إلى الحد الأقصى (ADET) ثم تريد إضافة الباقي إلى آخر.

هذا حساب صعب للغاية لأنه يجب عليك مقارنة صفوف مختلفة والعودة وتغيير القيم في صفين واحد أو ربما لتتبع كل معاملة مخزون.

هناك مايو كن وسيلة للقيام بذلك بدون مؤشر ، كما يقترح الآخرون. لكنني أعتقد أنه إذا تمكنت من إعادة ترتيب طاولاتك وتخزين البيانات بطريقة مختلفة ، فقد تكون قادرًا على جعل المشكلة أسهل.

على سبيل المثال ، بدلاً من تتبع الأسهم في نفس الجدول الذي يسجل معاملات الأسهم ، هل يمكن أن يكون لديك جدول منفصل مع أعمدة "Product_id ، depo_id ، المبلغ" الذي يتتبع إجمالي المبلغ لكل منتج في كل DEPO في وقت واحد ؟

تغيير تصميم قاعدة البيانات مثل هذا قد يجعل الأمور أسهل.

أو ... بدلاً من استخدام E_Cikan لتتبع ما يستخدم, ، استخدمه لتتبع ماذا تبقى. والحفاظ على قيمة E_CIKAN في كل صف. لذلك كلما دخل المخزون أو خارجه ، أعد حساب E_cikan في تلك المرحلة الزمنية وقم بتخزينه في صف المعاملة (بدلاً من محاولة العودة إلى الصف الأصلي "في الصف" وتحديثه هناك). ثم لمعرفة الأسهم الحالية ، يمكنك فقط إلقاء نظرة على أحدث عملية نقل لهذا المنتج/DEPO.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top