LookUp ları nasıl hızlandırabilirim ?

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
freeman35
Admin
Mesajlar: 2380
Kayıt: 12 Haz 2003 04:05
Konum: merkez camii yanı

LookUp ları nasıl hızlandırabilirim ?

Mesaj gönderen freeman35 »

basit 2 table var, StokID miktar. StokID Lookup field ile Stok Table a bağlıyorum. Stok tabledada fazla birşey yok. Kodu adı brfiyat.Her iki table bağımsız yani lookup olmazsa sonderece hızlı çalışıyor, saniyeden daha hızlı. ama eğer lookup olursa nerdeyse 1 dk da açılıyor. Makinam P4 3ghz 1gb ram daha neyi artırayım :lol:
ha bu arada 9000 e yakın stok adedi var
bunu hızlandırmak için Fikir ve önerileriniz neler ?
Kolay gele
ZAGOR TENAY TÜRK'tür... TÜRK kalacak...
Zoru başarırım, İmkansız zaman alır
FreeMan 35.5

Soru sormaya üşenmiyorsan, sorunun çözümünü yazmaya da üşenme !!!
Kullanıcı avatarı
fahrettin
Admin
Mesajlar: 2619
Kayıt: 11 Haz 2003 10:38
Konum: İstanbul
İletişim:

Mesaj gönderen fahrettin »

Hocam bu bir lookup alan düşük performans sorunu değil bence... Eğer gerekli indexler de var ise (ki olmasa bile bu kadar uzun hayatta sürmez bence) farkı hissetmeyeceğiniz bir zamanda açılması lazım.... 10-15 tane lookup alan olsa bir kaç saniyelik gecikmeyi anlarım ama burada farklı bir mesele var bence....

AMA NE?

Ha bu arada lookupları hızlandırmanın en iyi yolu onları kaldırmaktır... ;) Query icinde join ile gerekli butun alanları getirip updateleri de TUpdateSQL ile yapmak performansı dehşet arttırıyor.... Bunu internet üzerindeki bir veritabanına ulaşmaya çalışan projemde yapıp perofrmans farkınıa gözlerime şahit ve dumur oldum...
* http://www.fahrettin.org Manzara Fotoğraflarım... :)
* http://delphiturkiye.gunduz.info Seminerler... ;)
* http://www.hakmar.com.tr Kalite bir haktır... 8)
Kullanıcı avatarı
freeman35
Admin
Mesajlar: 2380
Kayıt: 12 Haz 2003 04:05
Konum: merkez camii yanı

Mesaj gönderen freeman35 »

IB/Fb de lookuplar biraz ağır çalışıyor. Birde benim detail olarak kullandığım table aslında Stored Procedure. İşin tuhafı şu yukarıdada yazmıştım bağımsız olarak sonderece performanslı açılıyorlar.
bencede kaldırmak en iyisi ama başka çare yok kullanıcaz :)
join i kayıt girişlerinde kullanmadım hiç onu bir deniycem, IBX kullandığım için mecburen UpdateSQL kullanıyorum. Ben dip not geçeyim LookUp Field ların "LookUpCache" property si vardır bunu True yaparsanız özellikle IB/FB de çok fazla performans artıyor. Bende bunlarda açık :)
aşağıda tablo ve performas bilgilerini döküyorum çok ilginç sonuçlar.

bu stok yani detail table ın select query si

Kod: Tümünü seç

SELECT 
  SP_STOK_LST.SELF,
  SP_STOK_LST.KODU,
  SP_STOK_LST.ADI,
  SP_STOK_LST.BR_FIYAT,
  SP_STOK_LST.GIREN,
  SP_STOK_LST.CIKAN,
  SP_STOK_LST.KALAN,
  SP_STOK_LST.REZ_CIKAN,
  SP_STOK_LST.REZ_GIREN,
  SP_STOK_LST.REZ_KALAN,
  SP_STOK_LST.CAN_USE
FROM
  SP_STOK_LST
Buda performans detayı
Query Time
------------------------------------------------
Prepare : 0,00 ms
Execute : 141,00 ms
Avg fetch time: 141,00 ms

Memory
------------------------------------------------
Current: 1.009.096
Max : 1.043.656
Buffers: 2.048

Operations
------------------------------------------------
Read : 0
Writes : 3
Fetches: 7.375


Enchanced Info:
+--------------------------+-----------+-----------+---------+---------+---------+
| Table Name | Index | Non-Index | Updates | Deletes | Inserts |
| | reads | reads | | | |
+--------------------------+-----------+-----------+---------+---------+---------+
| FIS_DTL| 480 | 0 | 0 | 0 | 0 |
| STOK_KART| 35 | 0 | 0 | 0 | 0 |
+--------------------------+-----------+-----------+---------+---------+---------+

Aşağıdaki Stok listesini için gereken verilerin oluşturan Stored Procedure

Kod: Tümünü seç

CREATE PROCEDURE SP_STOK_LST 
RETURNS (
    SELF INTEGER,
    KODU VARCHAR (25),
    ADI VARCHAR (50),
    BR_FIYAT DOUBLE PRECISION,
    GIREN DOUBLE PRECISION,
    CIKAN DOUBLE PRECISION,
    KALAN DOUBLE PRECISION,
    REZ_CIKAN DOUBLE PRECISION,
    REZ_GIREN DOUBLE PRECISION,
    REZ_KALAN DOUBLE PRECISION,
    CAN_USE DOUBLE PRECISION)
AS
BEGIN
  FOR
    SELECT 
      STOK_KART.SELF,
      STOK_KART.KODU,
      STOK_KART.ADI,
      STOK_KART.BR_FIYAT,
      (SELECT OUT_VAL FROM SP_CALC (1,STOK_KART.SELF) )AS GIREN,
      (SELECT OUT_VAL FROM SP_CALC (2,STOK_KART.SELF) )AS CIKAN,
      (SELECT OUT_VAL FROM SP_CALC (3,STOK_KART.SELF) )AS KALAN,
      (SELECT OUT_VAL FROM SP_CALC (5,STOK_KART.SELF) )AS REZ_GIREN,
      (SELECT OUT_VAL FROM SP_CALC (6,STOK_KART.SELF) )AS REZ_CIKAN,
      (SELECT OUT_VAL FROM SP_CALC (7,STOK_KART.SELF) )AS REZ_KALAN,
      (SELECT OUT_VAL FROM SP_CALC (-1,STOK_KART.SELF) )AS CAN_USE
    FROM STOK_KART
    ORDER BY STOK_KART.KODU
    INTO :SELF,
         :KODU,
         :ADI,
         :BR_FIYAT,
         :GIREN,
         :CIKAN,
         :KALAN,
         :REZ_CIKAN,
         :REZ_GIREN,
         :REZ_KALAN,
         :CAN_USE
  DO
  BEGIN
    SUSPEND;
  END
END
Aşağıda Master table ve select query si var

Kod: Tümünü seç

SELECT 
  FIS_DTL.SELF,
  FIS_DTL.MST_ID,
  FIS_DTL.CARI_ID,
  FIS_DTL.STOK_ID,
  FIS_DTL.ADET,
  FIS_DTL.BR_FIYAT,
  FIS_DTL.ACT_TYPE
FROM
  FIS_DTL
ORDER BY
  FIS_DTL.SELF
Buda performans analizi
Query Time
------------------------------------------------
Prepare : 0,00 ms
Execute : 16,00 ms
Avg fetch time: 16,00 ms

Memory
------------------------------------------------
Current: 972.068
Max : 1.170.180
Buffers: 2.048

Operations
------------------------------------------------
Read : 0
Writes : 7
Fetches: 570


Enchanced Info:
+--------------------------+-----------+-----------+---------+---------+---------+
| Table Name | Index | Non-Index | Updates | Deletes | Inserts |
| | reads | reads | | | |
+--------------------------+-----------+-----------+---------+---------+---------+
| FIS_DTL| 118 | 0 | 0 | 0 | 0 |
+--------------------------+-----------+-----------+---------+---------+---------+

Buda problemli olanı yani iki table ın join sonrası
Query şu:

Kod: Tümünü seç

SELECT 
  FIS_DTL.SELF,
  FIS_DTL.MST_ID,
  FIS_DTL.CARI_ID,
  FIS_DTL.STOK_ID,
  FIS_DTL.ADET,
  FIS_DTL.BR_FIYAT,
  FIS_DTL.ACT_TYPE,
  SP_STOK_LST.SELF,
  SP_STOK_LST.KODU,
  SP_STOK_LST.ADI,
  SP_STOK_LST.BR_FIYAT,
  SP_STOK_LST.GIREN,
  SP_STOK_LST.CIKAN,
  SP_STOK_LST.KALAN,
  SP_STOK_LST.REZ_CIKAN,
  SP_STOK_LST.REZ_GIREN,
  SP_STOK_LST.REZ_KALAN,
  SP_STOK_LST.CAN_USE
FROM
  FIS_DTL
  INNER JOIN SP_STOK_LST ON (FIS_DTL.STOK_ID = SP_STOK_LST.SELF)
ORDER BY
  FIS_DTL.SELF,
  SP_STOK_LST.SELF
buda performans analizi
Query Time
------------------------------------------------
Prepare : 0,00 ms
Execute : 33.672,00 ms
Avg fetch time: 33.672,00 ms

Memory
------------------------------------------------
Current: 5.157.432
Max : 9.291.804
Buffers: 2.048

Operations
------------------------------------------------
Read : 0
Writes : 1
Fetches: 1.635.919


Enchanced Info:
+--------------------------+-----------+-----------+---------+---------+---------+
| Table Name | Index | Non-Index | Updates | Deletes | Inserts |
| | reads | reads | | | |
+--------------------------+-----------+-----------+---------+---------+---------+
| FIS_DTL| 51473 | 0 | 0 | 0 | 0 |
| STOK_KART| 8240 | 0 | 0 | 0 | 0 |
+--------------------------+-----------+-----------+---------+---------+---------+
anlıyan çözen beri gelsin :lol:
ZAGOR TENAY TÜRK'tür... TÜRK kalacak...
Zoru başarırım, İmkansız zaman alır
FreeMan 35.5

Soru sormaya üşenmiyorsan, sorunun çözümünü yazmaya da üşenme !!!
Kullanıcı avatarı
aslangeri
Moderator
Mesajlar: 4322
Kayıt: 26 Ara 2003 04:19
Konum: Ankara
İletişim:

Mesaj gönderen aslangeri »

S.A.
Tabloda null kayıtlar olduğu için olabilirmi :?:

Kod: Tümünü seç

FROM 
  FIS_DTL 
  INNER JOIN SP_STOK_LST ON (FIS_DTL.STOK_ID = SP_STOK_LST.SELF) 
yerine

Kod: Tümünü seç

FROM 
  SP_STOK_LST  
  INNER JOIN FIS_DTL  ON (FIS_DTL.STOK_ID = SP_STOK_LST.SELF) 
yapıp deneyebilirmisiniz?
niye?
select sırası ndan dolayı olabilir gibi bir his var içimde. Bilmiyorum ne kadar mantıklı ama
ilk inde her fis_dtl için sp_stok_list i okuyacak. ikincide her_sp_stok_list için fis_dtl okuyacak.
Sp_stok_list okumada diğerine göre biraz ağır kalıyor onu bir kere okuyalım daha hızlı olanı tekrar okumak yavaş olanı tekrar okumaktan iyidir.
Ne biliyim aklıma geldi işte. :idea:
Kolay gelsin.

Not: Eğer işe yaramazsa peşinene özürlerimi kabul et lütfen. :oops:
Duyduğun Şeylerin Söylediklerim Olduğuna Eminim Ama
Anladığın Şeylerin Anlatmak İstediklerim Olduğuna Emin Değilim
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Mesaj gönderen sadettinpolat »

bende birkaç kez bu tür durumlarla karşılaşmıştım.
join bazen anlayamadığım bir şekilde sorgu sonucunu çok uzatabiliyor.
join yerine uygun olarak left join veya right join kullanmayı deneyin.

hazır join meselesi açılmışken şunuda bir dipnot olarak söyleyelim.

joinleri kullanırken çok dikkatli olmak gerekiyor.
çünkü null değerler duruma göre sorgu sonuçlarına dahil edilmediğinden dolayı, doğru sonuçlar elde etmiş gibi görünüyor fakat aslında sonuçlarda eksiklikler olabiliyor.

onun için left join, right joinve join arasındaki temel farklılakları iyi bilmek gerekiyor.

join iki tablo arasında belirtilen şartlara tamamen uyan kayıtları seçer.
left join iki tablo arasında şartlara tam olarak uyan kayıtları seçer + fromdan sonra belirtilen tabloda belirtilen şarta uymayan kayıtlar varsa onlarıda seçer

right join iki tablo arasında şartlara tam olarak uyan kayıtları seçer + joinden sonra belirtilen tabloda belirtilen şarta uymayan kayıtlar varsa onlarıda seçer

ful join iki tablo arasında şartlara tam olarak uyan kayıtları seçer + her iki tabloda da belirtilen şarta uymayan kayıtlar varsa onlarıda seçer
Kullanıcı avatarı
fahrettin
Admin
Mesajlar: 2619
Kayıt: 11 Haz 2003 10:38
Konum: İstanbul
İletişim:

Mesaj gönderen fahrettin »

Freeman35 yazdı:join i kayıt girişlerinde kullanmadım hiç onu bir deniycem,
Zaten TUpdateSQL kullanıyorsan Query'de join olması bir şeyi etkilemeyecek... Ben boyle kullandım... Yani lookup olarak planladığım alanları Query icinde join ile gosterdim... Update ederken de ana tablodaki ID alanını update ettim...
* http://www.fahrettin.org Manzara Fotoğraflarım... :)
* http://delphiturkiye.gunduz.info Seminerler... ;)
* http://www.hakmar.com.tr Kalite bir haktır... 8)
Kullanıcı avatarı
gkimirti
Admin
Mesajlar: 1956
Kayıt: 02 Eyl 2003 04:44
Konum: İstanbul

Mesaj gönderen gkimirti »

fahrettin yazdı: Zaten TUpdateSQL kullanıyorsan Query'de join olması bir şeyi etkilemeyecek... Ben boyle kullandım... Yani lookup olarak planladığım alanları Query icinde join ile gosterdim... Update ederken de ana tablodaki ID alanını update ettim...
abi kafama takıldı simdi, updatesql hatta ibupdatesql kullanımını arastırdım biraz extra birkac avantajı dısında ibdataset ile aynı diyebilirim
asıl kafama takılan nokta lookup alanları join yaparak updatesql ile nasıl guncellenecegi?
mesela bir tane stok_giris tablosu olsun
alanlaı: s_gir_id (stok giris id) ,s_id (stok/urun id), adet
ve stok tablomuz olsun
alanları: s_id,s_ismi

bu iki tabloyu join yaparak s_gir, s_ismi,adet
seklindebir dataset elde etsek buradaki lookup alan s_ismi, nasıl guncellenecek

yada boyle bir sey yapılmasına gerek var mı?

Daha dogrusu siz ne sekilde kullanıyorsunuz abi bilemiyorum ama benim aklıma boyle bir ornek geldi
ÜŞENME,ERTELEME,VAZGEÇME
Kullanıcı avatarı
fahrettin
Admin
Mesajlar: 2619
Kayıt: 11 Haz 2003 10:38
Konum: İstanbul
İletişim:

Mesaj gönderen fahrettin »

eger program internetteki bir veritabanına baglaniyorsa o zaman lookup alanlar icin arka planda yapılan islemlerin yani her kayıt icin ayrı query create edilerek data getirilmesinin performansı nasıl yavaşlattığını goreiliyorsun.... Netekim ben de gordum....

Onun uzerine query icinde join yapıp verdiğin örnekteki mantık ile s_gir, s_ismi,adet ve bunlara ilaveten s_id alanini da iceren bir dataset olusturuyorum. guncelleme sirasinda da dogal olarak s_gir_id (stok giris id) ,s_id (stok/urun id), adet alanlarını güncelliyorum.... Sadece afterpostta query'nin refresh olabilmesi icin bir close, open gerekli o kadar... Fakat buna karşılık performans çok artıyor...

Tabi bu çok performans artışı göreceli... Yani lokal networkte fark hissedilemez ama uzak bir bağlantı varsa ve hele bir de lookup sayısı bir kac tane veya daha fazla ise fark çok açık ara oluyor....
* http://www.fahrettin.org Manzara Fotoğraflarım... :)
* http://delphiturkiye.gunduz.info Seminerler... ;)
* http://www.hakmar.com.tr Kalite bir haktır... 8)
Kullanıcı avatarı
gkimirti
Admin
Mesajlar: 1956
Kayıt: 02 Eyl 2003 04:44
Konum: İstanbul

Mesaj gönderen gkimirti »

Bu sekilde kullanımda lookup alanın sagladıgı acılırkutu kullanılmamıs oluyor.
yani stok_giris tablosuna bir kayıt eklenecek,
eklenecek urunu acılır kutudan secmek daha pratik olmazmı,
yoksa bu tip kullanımda sadece guncelleme mi yapılmalı, ekleme yapılmamalı mı?
ÜŞENME,ERTELEME,VAZGEÇME
Kullanıcı avatarı
freeman35
Admin
Mesajlar: 2380
Kayıt: 12 Haz 2003 04:05
Konum: merkez camii yanı

Mesaj gönderen freeman35 »

@aslangeri söylediğinide denedim ama değişen bir şey yok.
Null alalar içinse kesinlikle yok :) eskiden gelen bir alışkanlık. sum vs gibi işelemler yapıcağım alanlara kesinlikle değer atarım. Ayrıca Index veririm. özellikle sum aldığınız alanlarada bir index tanımlayın. Performans artıyor. Yukarıdaki sorunumdada master detail alanlarda index tanımlı, üstelik foreingkey tanımlı her iki tarafında null olma olasılığı yok. kriter olarak kullanacağım alanlara mutlaka değer veriyorum, null olması yerine o alana -1 atmak daha mantıklı geliyor.
Aklıma Recep in kullandığı yöntem geliyordu onuda denedim,Yani Lookup için kullanacağım Table ı memTable a alayım dedim, ama onunda okunması yani stok bilgilerinin olduğu table anında açılıyor ama o bilgileri ki 9000 adet kadar bunun memtable a okunması için geçen süre aynı :(
Şimdilik çare olarak Stok listesinin yanına gelecek olan envanter miktarlarını koymıyacağım, ayrı bir rapor olarak ekliyeceğim.

@Fahrettin, ne yalan söyliim walla benden anlamadım, nasıl bir yöntem kuallandığını. Ben giriş işlemlerini grid içinden yaptırtıyorum, Grid cxGrid. Her satır için lookup ile isimleri geliyor.satır bittiğinde alt satıra geçip devam ediliyor. Şimdi join kullanabilmem için ona değer yani bağlı olduğu Integer alanın değeri olması gerekiyorki string döndürsün, ama yeni kayıt sırasında integer değer yokki? ve post edilmediği içinde string değeri bulabilirmi ?

benim kullandığım, bu grid içinde tüm satırları dolduruyorlar, bunlar Fiş Kaydet denildiğinde Transaction commit ediliyor. Yani bir fiş mantığı var satır olarak değil tüm alanlar aynı anda kaydediliyor.

Kolay gele
ZAGOR TENAY TÜRK'tür... TÜRK kalacak...
Zoru başarırım, İmkansız zaman alır
FreeMan 35.5

Soru sormaya üşenmiyorsan, sorunun çözümünü yazmaya da üşenme !!!
Kullanıcı avatarı
fahrettin
Admin
Mesajlar: 2619
Kayıt: 11 Haz 2003 10:38
Konum: İstanbul
İletişim:

Mesaj gönderen fahrettin »

Benim yaptığım işi izah edemedim galiba...
Baştan alayım:
Bir kere sonuç olarak sistemin çalışmasında hiç bir fark yok. Goruntu tamamen aynı... Sadece arkadaki yapı değişerek perofrmans artıyor....
Ornek: Persoenl tablosu, PERSONEL_NO, AD,BOLUM_NO olsun
bolum tablosu da BOLUM_NO, AD olsun...

TQuery icine:

Kod: Tümünü seç

Select P.PERSONEL_NO, P.AD, P.BOLUM_NO, B.AD as BOLUM
from PERSONEL as P, BOLUM as B
where P.BOLUM_NO=B.BOLUM_NO
yazıyorum.

TQuery'nin de
cacheupdate=True
requestlive=false
yapıp TUpdateSQL ile de bagliyorum. Tabi update edilecek alanlar sadece (P.PERSONEL_NO, P.AD, P.BOLUM_NO ) olarak seciliyor....

Yeni bir kayıt acildiğinda herşey zaten boş gorunuyor... BOLUM degeri yine combobox'tan seciliyor... Tek farkla ki o ada klasik bir DBLookupCombobox degil. icinin rauntime'da kod ile dolduruldugu bir DBCombobox . Secilen BOLUM'un BOLUM_NO degeri tablodaki alana atanıyor...

AfterPost eventine TDatabase'in Applyupdates metodu çağırılıyor. Ve tabi ki query'nin post edilmiş kayıdın joinini yapıp getirebilmesi icin bir close, open.

Hepsi bu....
* http://www.fahrettin.org Manzara Fotoğraflarım... :)
* http://delphiturkiye.gunduz.info Seminerler... ;)
* http://www.hakmar.com.tr Kalite bir haktır... 8)
Kullanıcı avatarı
freeman35
Admin
Mesajlar: 2380
Kayıt: 12 Haz 2003 04:05
Konum: merkez camii yanı

Mesaj gönderen freeman35 »

hah şimdi tamam işte :) jeton köşeli kusura bakma :)
Bana sorarsan kendine iş çıkartmışsın :) nedini şu runtimeda combobox ın içeriğini gene db den manual okuyup alıyorsun ve arka planda sen kod yazarak işlem yapıyorsun. Bu benim için yani tam istediğim değil. Yukarıda yazmıştım MemTable a almaya kalktığımdada 1 dakika kadar bekliyorum.
Kuzen senin proje için bir deneme yapabilirmisin ? yani fırsatın varsa deneyip sonucu bildirirsen sevinirim. Bu olayı normal Lookup larla yapıp, TField özelliklerinde LookUpCache i True yapıp denermisin? buda lookup field değerlerini memory ye alıp herseferinde db üzerinden okumuyor, memoryden okuyor diye biliyorum. Buda senin manual olarak dblookup içini doldurmaya benziyor galiba.

Aslında benim işimi görecek aslında herkezin işini görecek olan bir component, bunu devex e yazayım bari :) TField a lookup tanıtmayayım, zaten devex string değeri saklıyor bunu bassın gidip herseferinde db ye bakmasın. ozaman benim lookupfield tanıtmama gerek kalmaz. aslında bunu yapıyor, ama cxgrid içinde bunu yapmıyor? illaki lookup field dan gelen değeri yazmaya çalışıyor.

Kolay gele
ZAGOR TENAY TÜRK'tür... TÜRK kalacak...
Zoru başarırım, İmkansız zaman alır
FreeMan 35.5

Soru sormaya üşenmiyorsan, sorunun çözümünü yazmaya da üşenme !!!
Cevapla