Bu işlemin başka yolu varmı?

Firebird ve Interbase veritabanları ve SQL komutlarıyla ilgli sorularınızı sorabilirsiniz. Delphi tarafındaki sorularınızı lütfen Programlama forumunda sorunuz.
Cevapla
baloglurecep
Üye
Mesajlar: 261
Kayıt: 21 Tem 2006 04:59
İletişim:

Bu işlemin başka yolu varmı?

Mesaj gönderen baloglurecep »

Arkadaşlar hepinize sağlıklı güzel günler diliyorum. Bir projem var. yaklaşık 500 e yakın kullanıcısı var. cari program. sorunum müşteri extre tablosunda son durum bakiye işlemi.
Biraz anlatayım. Extre tablosunda son durum ve son durum 2 adında 2 alan var. Bu alanlara extre tablosundaki tarih ve ide göre sıralanıp ilk kayıttan başlayıp döngü ile her satırdaki işleme göre o andaki bakiyeyi atıyor son durum 2 alanına ise bir önceki bakiye atılıyor ki 2 tarih arası sorgularda devredeni görmek için. sondurum2 alanı 2 tarih arası sorgulama yapılınca gösteriliyor extre formunda devreden adı altında.

Örnekle açıklamak gerekirse

1. İşlemde satış yapılmış 5 tl lik son durum bakiye 5 tl - sondurum2 ise 0 olmuş.
2. İşlemde 1 liralık satış yapılmış son durum 6 lira - sondurum2 ise 5 olmuş.
3. İşlemde 5 tl lik ödeme yapılmış son durum 1 lira sondurum2 ise 6 olmuş.
4. İşlemde 8 lira satıl olmuş son durum tekrar artarak 9 lira - sondurum2 ise 1 olmuş.
5. İşlemde 8 liralık satış olmuş son durum 17 tl - sondurum2 ise 9 olmuş.
6. İşlemde 5 tl lik ödeme ypılmış son durum 12 ye - sondurum2 ise 17 düşmüş.
7.işlemde 160 tl borç işlenmiş son durum 172 tl - sondurum2 ise 12 olmuş

döngüye girip işlem türüne bakıp borcçsa bakiyesi artan, ödeme ve iade ise bakiye azalan bir şekilde önce değişkene en sonda ilgili alanlara editlenip post ediliyor. kayıt sayısı az olan işlemlerde süre az ama 1000 leri geçince ( bbu şimdi bin olur yarın yüzbin olur bilinmez) müthiş zaman almakta. 2300 kayıt olan extre 4 çekirdeğe sahip 4 gb li ram olan pc de yaklaşık 6 dakka sürüyor. siz düşünün bu 10000 olsa 100 000 olsa ne olacak.

Bu işlemi başka nasıl yapabilirim? bu konuda her fikre öneriye açığım. firebird 2.0 veri tabanı kullanmaktayım. Herkese saygılar sunarım.

kodum şu şekilde.

Kod: Tümünü seç

procedure Talinanlar_form.SonDurumHesapla(ILK:Boolean);
VAR BAKIYE,BAKIYE2 : DOUBLE;
I:Integer;
BEGIN   

IF DM.extre_query.RecordCount=0 THEN Exit;


order:='TARIH,ID';
Filitre;

dm.extre_query.First;
BAKIYE:=0;  // bakiye değişekni sıfırlanıyor
I:=1;
  WHILE NOT(dm.extre_query.EOF) DO   // döngü yapıyor
    begin
    Application.ProcessMessages;

    bsSkinLabel1.Caption:='HESAPLANAN İŞLEM SAYISI / TOPLAM İŞLEM SAYISI : ' + IntToStr(I)+' / '+IntToStr(dm.extre_query.RecordCount);

    I:=I+1;

    BAKIYE2:=BAKIYE;// burada bakiye 2 alanı devreden için kullanıldığından bir önceki bakiyeyi tutması için eşilendi.

    IF (dm.extre_query.FieldByName('TOPLAMTUTAR').AsFloat> 0) and (dm.extre_query.FieldByName('TUR').AsString <> 'İADE')THEN
    BAKIYE:=BAKIYE+dm.extre_query.FieldByName('TOPLAMTUTAR').AsFloat;
    IF dm.extre_query.FieldByName('ODEME').AsFloat> 0 THEN
    BAKIYE := BAKIYE -  dm.extre_query.FieldByName('ODEME').AsFloat;
    dm.extre_query.Edit;
    dm.extre_query.FieldByName('SON_DURUM').AsFloat:= BAKIYE;  // son duruma değişeken toplanan bakiyeyyi atıyorum
    dm.extre_query.FieldByName('SON_DURUM2').AsFloat:= BAKIYE2;  // DEVREDEN BAKİYE ICIN
    dm.extre_query.Post;
    dm.extre_query.Next;
    end;

end;
akdatilla
Üye
Mesajlar: 292
Kayıt: 02 Nis 2006 06:04
Konum: Antalya

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen akdatilla »

merhaba
1) işlem esnasında, dm.extre_query datasetinin herhangi bir datasource'e bağlı olmadığından emin ol.
Eğer datasource nesnesi illaki kullanman gerekiyorsa datasource nesnesini işlemin başında enabled ozelliğini false vererek kapat, işlemden sonra enabled ozelliğini aç. Application.processmessages komutu her döngü adımında değilde her 20 dongu adımında 1 çalışsın.

2) ekstre hesabını yapan bir stored prosedür hazırla, ekstre hesabını stored prosedür yapsın. forumda muhtemelen bununla ilgili örnekler vardır.
baloglurecep
Üye
Mesajlar: 261
Kayıt: 21 Tem 2006 04:59
İletişim:

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen baloglurecep »

Hocam döngü ile veri tabanı içinde stored procedur ile bu hesaplatmayı nasıl yapabilirim? basit bir örnek iletmeniz mümkünmü?

Aplication progresmesajın her düngüde ne gibi olumsuzluğu var.
Saygılar....
baloglurecep
Üye
Mesajlar: 261
Kayıt: 21 Tem 2006 04:59
İletişim:

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen baloglurecep »

Atilla hocam dediklerinizi yaptım. Data sourcu kapattım ve döngü sonunda açım. Ayrıca aplication proggresmessageyi kaldırım. hiç kullanmadım. 6 dk süren işlem 25 sn yeye düştü.
Eğer dediğiniz gibi bunu veri tabanına storedprocedurle yaptırtabilirsek daha da hızlanacaktır. Ancak nasıl döngü ve editleme yaptıracağımı bulamadım procedurede. Bu konuda yardımlarınızı talep eder saygılarımı sunarım.
Kullanıcı avatarı
unicorn64
Üye
Mesajlar: 919
Kayıt: 04 Nis 2006 08:56
Konum: yine yeniden Ankara ^_^

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen unicorn64 »

editleme -> kaydı güncelleme -> update
bazen yükselmek için önce dibi görmek gerekir...

forumda soru sormadan önce bakılmalı bence
daha fazlası için...

yürümeyi öğrenmeden koşmaya çalışanlar için, tökezleyip düşmek kaçınılmazdır...

Resim
emin_as
Üye
Mesajlar: 559
Kayıt: 01 Eki 2008 10:05
Konum: izmir
İletişim:

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen emin_as »

Zamanında devir işlemleri için aşagıdaki stored procedure u yazmıştım, inceleyip kendine göre uyarlarsın.

Kısaca bilgi vermek gerekirse:
for select alan1,alan2,... from tablo into :degisken1,:degisken2, ..
do
begin
... islemlerini burada yapacaksın.
end

Bilgi dönüşü yaptırmayacaksan, suspend komutuna ihtiyacın yok.

Kod: Tümünü seç

create or alter procedure YILSONUDEVIR (
    STOKAKTAR char(1),
    DEFTERSIL char(1),
    TAMIRKART char(1))
returns (
    SONUC integer)
as
declare variable RAFNO1 varchar(10);
declare variable DEVMIK numeric(16,2);
declare variable DEVTUT numeric(16,2);
declare variable ALMIK numeric(16,2);
declare variable ALTUT numeric(16,2);
declare variable VERMIK numeric(16,2);
declare variable VERTUT numeric(16,2);
declare variable BAKMIK numeric(16,2);
declare variable BAKTUT numeric(16,2);
declare variable TIP1 varchar(1);
declare variable TUT1 numeric(16,2);
declare variable MIK1 numeric(16,2);
declare variable SIRANO1 integer;
begin
  if (stokaktar ='A') then
  begin
    FOR
      select RAFNO,DEVIR,DEVIRTUTARI
        from STOK
        into :RAFNO1,:DEVMIK,:DEVTUT
      do
        begin
          if (devtut is null) then devtut=0;
          if (devmik is null) then devmik=0;
          vermik=0;
          vertut=0;
          almik=0;
          altut=0;
          bakmik=0;
          baktut=0;
          for
            select s.tip,sum(s.miktar),sum(s.tutar) from stmar s
              left join stmak h on h.tip=s.tip and h.makbuzno = s.makbuzno
            where rafno=:rafno1
            group by s.tip
            into :tip1,:mik1,:tut1
            do
              begin
              if  (mik1 is null) then mik1=0;
              if  (tut1 is null) then tut1=0;

              if (tip1='A') then
              begin
                almik=mik1;
                altut=tut1;
              end
              if (tip1='B') then
              begin
                vermik=mik1;
                vertut=tut1;
              end
            end
         bakmik = devmik + almik - vermik;
         baktut = devtut + altut - vertut;

        insert into stok(devir,devirtutari)
         values (:bakmik,:baktut);
         vermik=0;
          vertut=0;
          almik=0;
          altut=0;
          bakmik=0;
          baktut=0;
     end
     delete from stmar;
     delete from stmak;
   end
   if (DEFTERSIL = 'A') then
   begin
     delete from defhar7;
   end
   if (TAMIRKART = 'B') then
   begin
     for
       select t.sirano from tamir t
         where not (t.bitistarih is null)
        into :sirano1
       do
       delete from tamhar h
          where :sirano1=h.sirano;
     delete from tamir
        where not (bitistarih is null);
   end
   if (TAMIRKART = 'C') then
   begin
     delete from tamhar;
     delete from tamir;
   end
end^
varyemez
Üye
Mesajlar: 262
Kayıt: 01 Oca 2009 11:00
Konum: Bursa
İletişim:

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen varyemez »

Benim de benzer bir sorunum var. Burada görünce yeni başlık açmayayım , size danışayım.. Atila hocamızın anlatıklarını uygulayacağım.
XML dosyaları okuyup içindekileri tabloya aktaran bir projemiz var. Yerine göre bir xml içinde 5 10 bin kayda kadar varabiliyor. xml in validasyonunu yaptıktan sonra malum parseleme işini yapıp IBquery veya IBDataseti kullanarak veritabanına alıyor. Bazan bir defadaki xml sayısı 20 25 tane oldu mu da tümünün açılıp içeri alınması 1 2 saati buluyor.
Her query ve datasete rutin olarak bir datasource eklemek zorunda değiliz o zaman Atilla hocam öyle mi? Datasource kullanımını biraz açarmısınız , nerde ne zaman kullanacağız.

bir sorum daha , Emin bey in anlattığı gibi SP içinde yaptırsak bunu , oluşabilecek hataları nasıl yakalarız. Daha açıkçası bir xml içinde tek bir kayıt alınırken bile hata oluşsa tüm o xml ile ilgili kayıtların append işlemini iptal (canceluptates , veya rollback) etmek istiyorum. Sonuşta da log dosyasına gönderilmek üzere bir hata kodu gelsin.
orhancc
Üye
Mesajlar: 585
Kayıt: 24 Ağu 2010 02:14
Konum: İstanbul / Kadıköy
İletişim:

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen orhancc »

1-2 saat süren işlemde kaç kayıt yapılıyor ve kaydı nasıl yapıyorsunuz ?
akdatilla
Üye
Mesajlar: 292
Kayıt: 02 Nis 2006 06:04
Konum: Antalya

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen akdatilla »

varyemez yazdı: XML dosyaları okuyup içindekileri tabloya aktaran bir projemiz var. Yerine göre bir xml içinde 5 10 bin kayda kadar varabiliyor. xml in validasyonunu yaptıktan sonra malum parseleme işini yapıp IBquery veya IBDataseti kullanarak veritabanına alıyor. Bazan bir defadaki xml sayısı 20 25 tane oldu mu da tümünün açılıp içeri alınması 1 2 saati buluyor.
Her query ve datasete rutin olarak bir datasource eklemek zorunda değiliz o zaman Atilla hocam öyle mi? Datasource kullanımını biraz açarmısınız , nerde ne zaman kullanacağız.
Datasource nesneleri datasetler ile data kontroller arasında bağlantıyı sağlamak için kullanılır. Data kontrol nesneleri; programcılar için bilgilerin kayıt ve gözlem işlerini yapabilmeleri için büyük kolaylıklar sağlamakta. Programlarınızda data kontrolleri kullanmaya devam edebilirsiniz. Ancak programınızda bir döngü içerisinde onlarca kayıt işlemi yapacaksanız kullandığınız datasetin data kontrollere olan bağlantısının kesilmesi gerekir. Çünkü dataset içerisinde her bir hareket data kontrollerin güncellenmesini gerektirir.

Yukarıda bahsettiğiniz işlemi yapmak için hiçbir datasource'e bağlı olmayan sıfır bir dataset/query nesnesi ekleyin. Kayıt esnasında dataseti aktifleştirin ve bütün kayıt işlemlerini döngü içerisinde yapın.
Döngü içerisinde çok sık olmamak şartı ile application.processmessages; komutunu kullanın.
Örnek:

Kod: Tümünü seç

if (j mod 50)=0 then application.processmessages;
kayıt işlemleri tamamlandıktan sonra daha once kullandığınız data kontrollere bağlı olan asıl dataset nesnenizi kapatıp tekrar açın (dataset.close;dataset.open;).
belki daha açıklayıcı olur diye aşağıya örnek bir kod bloğu veriyorum. Kolay gelsin.

Kod: Tümünü seç

procedure kayitislemi;
var
j:integer;
hmsj:string;
begin
hmsj:='';

kayitdataset.close;
kayitdataset.open;
for j:=0 to xmlverisayisi-1 do
begin
try
kayitdataset.append;
kayitdataset.fieldbyname('alan1').value=xmlveri[j].deger1;
kayitdataset.fieldbyname('alan2').value=xmlveri[j].deger2;
...
kayitdataset.post;
except
hmsj:=hmsj+'hata mesaji'#13#10;
if kayitdataset.state=dsInsert then kayitdataset.cancel;
if (j mod 50)=0 then application.processmessages;
end;
if hmsj<>'' then showmessage(hmsj);
kayitdataset.close;
displaydataset.close;
displaydataset.open;
end;
varyemez
Üye
Mesajlar: 262
Kayıt: 01 Oca 2009 11:00
Konum: Bursa
İletişim:

Re: Bu işlemin başka yolu varmı?

Mesaj gönderen varyemez »

Daha önce atilla beyin yazdığı gibi normal ibdataset üzerinde (ama datasource kullanarak enabled) append yaptırıyodum.
10 15 bin kaydı 1 saatten fazla zamanda ekliyordu..
şimdi ise:
append işini SP ye koydum , diğer tarafta da başka bir tablonun datasetini kullanıyorum. onun datasource unu kapattım.
IBStoredProc.paraömyname(...) lerle yaptığımda işlem müthiş hızlandı. 450 dosya (zip) indirmesi , bunların zip olarak tabloya (blob) kaydı , sonra bunların açılıp xml lerin işlenip SP ile olan tabloya 155 bin kaydın aktarılması toplam 12 dakika sürdü. Her işlem loglanıyor bir de. Ddosyaları indirmek ve blob alana geçirmek 7 dakika. tabloya almak 5 dakika.
Çok teşekkürler atilla bey.
Aynı yöntemi birr de update işlemi olan bir proc um var ona uygulayayım dedim hata veriyor.
soap ile çektiğim bir datasetimiz var diyelim. httprio üzerinde , array olarak. bundaki UC alanını tabloya update edecek.
Bu array içinde de yerine göre 10 15 bin kayıt olabiliyor. Normal şekilde bunları önce geçici bir tabloya alıp oradan asıl tabloya güncelleme de yaptırabiliyorum ama zaman kısalır mı diye direkt SP ile denemek istedim

for I = 0 to length(cikis.URUNLER) -1;
dm.ibsp2.close;
dm.ibsp2.Parambyname('GUC').asstring:=cikis.URUNLER.UC;
dm.ibsp2.Parambyname('GSN').asstring :=cikis.URUNLER.SN;
dm.ibsp2.Parambyname('GGTIN').asstring :=cikis.URUNLER.GTIN;
dm.ibsp2.prepare;
dm.ibsp2.ExecProc;
end;


SP ise aşağıdaki şekilde :

Kod: Tümünü seç

 UPDATE PTABLO   SET  PTABLO.UC = :GUC 
  WHERE PTABLO.GTIN= :GGTIN  AND PTABLO.SN= :GSN;
SUSPEND:
Cevapla