Laravel Türkiye Discord Kanalı Forumda kod paylaşılırken dikkat edilmesi gerekenler!Birlikte proje geliştirmek ister misiniz?
  • YardımLaravel
  • E-Ticaret Veri Tabanı Tablosu İçin Performans İle İlgili Basit Soru

Rest apide bunu kaynak olarak verdiğinizi varsayarsak bu kadar alanı client attığı isteğinde hepsini kullanmayacaktır o yüzden burada ya grapqQL gibi bir yapı kullandırtın clienta yada client ne istiyorsa siz ozel olarak donun.Gereksiz her data sizden gidecektir.O yüzden yük altında zorlanacaktır sisteminiz.

Bir diğer dezavantajı human readable dedikleri şey..siz okuyamıcaksınız hızlıca.Zaman kaybı yaratacaktır size.
Her ne kadar ilişkilere bölünmesini soylemek istesemde..gereksiz ilişkide kötüdür.Bir orta yolunu bulmalısınız.
Onun haricinde @sineld hocamın dediği gibi where yan tümceleriniz doğru indexleri kullanması önemlidir.
Ornegin @mgsmus tan öğrenmiştim bende bunu paginate() methodu yerine simplePaginate() kullanmanız daha iyi gibi durur bazı durumlarda...

Dediğim gibi human readable yonunden kotu bir tablo ama iyi yonetiyorsanız cok sorun cıkarmaz.
Ancak resim alanlarınızı ben olsam ayırırdım.

    Ben olsam;

    • Fiyatlar
    • Sipariş Miktarları
    • Ölçüler
    • Özel Alanlar
    • Resimler
    • Seo
    • Durumlar

    Diye parçalara bölerdim.

      mgsmus

      Hocam verdiğiniz dökümanları incelemek üzere kaydettim başladımda incelemeye, ama tabiki direk burada sizden aldığımız cevaplar gibisi gelmeyecek.

      İndex konusunu

      https://laravel.gen.tr/d/4136-database-index

      Gayet net anladım. Ama bunu laravel 8 de controller kısmında nasıl kullanabiliriz

      https://laravel.com/docs/8.x/migrations#indexes

      Laravel dökümanlarından inceliyorum ama en sağlıklı bilgiyi yine sizden öğrenmek daha iyi olacak.

      Daha önceden bahsettiğim bir haber sistemim vardı orada şuan için kullanacağım ama hangi alanlarda kullanmam gerektiğini tam olarak idrak edemedim.

      Mesela bunları haber kategorilerine göre mi yapmalıyız eğer böyle olacaksa bir kategori diğerine göre çok fazla içerik barındırabilir bunuda bölmek gerekecek. Bunu yaparken birde pluck gibi bağlantılar kullanarak indexleri ayrı ayrı mı oluşturacağız burası çok karıştı eğer müsaitseniz basit örnekler ile verebilirseniz çok memnun olurum

      Çünkü haberler kategoriler dışarısında çok fazla birbirinden ayrılmıyor kendi içlerinde şu tabloları tutuyor sizce ne yapılmalı?

      $table->charset = 'utf8mb4';
      $table->collation = 'utf8mb4_general_ci';
      $table->bigIncrements('id');
      $table->unsignedBigInteger('yazar_id');
      $table->string('baslik');
      $table->string('kisa_baslik');
      $table->text('ozet');
      $table->string('url');
      $table->text('icerik');
      $table->text('etiket')->nullable();
      $table->string('resim_1')->nullable();
      $table->string('video')->nullable();
      $table->string('seo_baslik')->nullable();
      $table->string('seo_aciklama')->nullable();
      $table->string('seo_kelime')->nullable();
      $table->integer('durum')->default(1);
      $table->integer('durum_yorum')->default(1);
      $table->integer('durum_reklam')->default(1);
      $table->integer('durum_alan1')->default(0);
      $table->integer('alan1_siralama')->default(1);
      $table->integer('durum_alan2')->default(0);
      $table->integer('alan2_siralama')->default(1);
      $table->integer('durum_alan3')->default(0);
      $table->integer('alan3_siralama')->default(1);
      $table->integer('durum_alan4')->default(0);
      $table->integer('alan4_siralama')->default(1);
      $table->integer('durum_alan5')->default(0);
      $table->integer('alan5_siralama')->default(1);
      $table->integer('durum_alan6')->default(0);
      $table->integer('alan6_siralama')->default(1);
      $table->timestamps();
      $table->foreign('yazar_id')
      ->references('id')
      ->on('haber_yazar');

      Bu arada burada verdiğim kodu henüz sizin tavsiyelerinize göre güncellemedim. Bunlarıda güncelleyeceğim birazdan

              $table->index([
                  'baslik',
                  'kisa_baslik',
              ], 'index_ismi');

      Şeklinde index oluşturursunuz; dizi içinde index alanlarının isimlerini yazarsınız. index_ismi kısmının benzersiz olmasına dikkat etmelisiniz. opsiyoneldir ancak çok sayıda index olması durumunda sorun yaşayacağınızdan elle tanımlanmasını öneririm.

        sineld Bu dediğinizi migrations'da oluştururken yapıyoruz değil mi?

        Peki controller'da verileri çekerken ayrı bir şey yapmamıza gerek kalmıyor değil mi? Öyleyse normal çektiğimiz gibi çekiyoruz verileri diye anladım

        Bu basit olacak ama bu örnek için ;

        `
        public function index()
        {

            $data = Haber::with('haberKategoriler')
                ->latest('created_at')
                ->get();
        
            return view ('SS.haber.index',compact('data'));
        }`

        Burada adminde tüm verileri çektik, ama detay sayfalarında da mantık olarak bu şekillerde yazacağız herhalde (paginate) v.s. alanlarını henüz hazırlamadım o yüzden çok boş kaldı)

        Bu arada
        $table->index([
        'baslik',
        'kisa_baslik',
        ], 'index_ismi');

        integer, boolean, string gibi alanlar tanımlamıyor muyuz bu alanlarda?

        Text dışındaki alanları ekleyebiliyorsunuz. text alanlar için farklı bir index yapısı mevcut, onunla da ilgili örnek verebilirim.

        Migrations içinde yapıyorsunuz, controller vs her yerde standart kullanıyorsunuz, ek bir şey yapmanıza gerek yok.

          sineld Peki bunu nasıl yapacağız?

                  $table->index([
                      string('baslik'),
                      integer('kisa_baslik'),
                  ], 'index_ismi');

          Gibimi olacak acaba?

          Eğer text içinde örnek verebilirseniz çok sevinirim.

          mgsmus Hocam burada konuşulanları benimle paylaştığınız diğer konulara eklememiz gerek diğer faydalanacak kişiler için çok açıklayıcı oldu bu konu.

          Aslında sitede böyle bir yer olsa çok lezzetli olur top soruların olduğu alan herkesin çok işine yarar.

          Çok teşekkür ederim ilgi alakanız için hocam.

          sineld Sanırım şimdi çözdüm

          İndexleride aşağıda ayriyetten veriyoruz sanırım. Foreign key gibi.

              {
                  Schema::create('haber_deneme', function (Blueprint $table) {
                      $table->bigIncrements('id');
                      $table->string('baslik');
                      $table->string('ozet');
                      $table->string('url');
                      $table->string('aciklama');
                      $table->index([
                          'baslik',
                          'ozet',
                      ], 'haberindex1');
                  });
              }

          Bunu yaptık ve tüm olay halloldu sanırım? Yani bundan sonra laravel bizim için controller'da haberi çekerken sadece where ile başlık ve özeti çekeceksek mysql de index eklenmiş olduğunu görecek ve farklı bir koda gerek kalmadan daha az yorulacak ve performansımız katlanacak, birde bunları yaptıktan sonra farklı tablolara bölmeye gerek kalmıyormu tabi bu çok göreceli bir kavram ama ayrı ayrı uğraşmak yerine index yapılırsa performansta ayrı ayrı yapmak gibi artacak diye düşünüyorum doğru mudur?

          Burada ön tarafta haber sitesinde anasayfa'da sadece haberin başlığı ve özetini çekeceksek böyle bir örnek yapmanız mümkün mü en doğrusu nasıl olacaktır?

            Hepsi bu kadar, yapacağın başka bir şey yok.

            • mgsmus

              Seviye 1382
            • Düzenlendi

            byhk44 Başlık, özet, içerik... gibi içinde arama yapılacak alanlara düz index atılmaz. Onlarda full-text index kullanılır çünkü onlarda bir şey bulmaya çalışsanız = değil LIKE kullanırsınız ama LIKE index kullanamadığı için yerine full-text index kullanılır. Bunun gibi birçok konu var o yüzden index konusu sizin araştırmanız gereken bir konu. Forumdan ziyade, bu işi öğrenmek istiyorsanız kendi araştırmanızı yaparak ilerlemeniz doğru olur. Forumda, ilerledikten sonra gelip takıldığınız yerleri sorabilirsiniz. Şu aşamada sorduğunuz soruların çoğunun cevabı için kitap yazıyorlar.

            Laravel değil SQL düzeyinde nasıl yapılıyor, ne ifade ediliyor onu öğrenin. Bu konu Laravel ya da PHP değil veritabanı konusu.

              Baslık ve ozet icin niye index attınız ki..arama mı yaptırcaksınız.
              Yalnış bir yol bence.uygulamanız ne kadar büyücek bilmem ama.Tablo büyüdükce indexleriniz de bir işe yaramaz.Hele ki LIKE yapacaksanız full-text-index kullanmanız lazım.Ama bana kalırsa database de arama yapmayın.Bunun icin elasticsearch gibi 3.parti uygulamaları kullanın.

                • byhk44

                    Seviye 18
                  • Düzenlendi

                  deathisonitsway

                  Şimdi anladım, arama yapmak dediğiniz search bar üzerinden bir arama yapmak, yani anasayfada içerikleri gösterirken yapıyoruz sandım.

                  Şu şekilde bir veri için 20 tane sütun var ama ana sayfada sadece 3 tane görülecek başlık özet açıklama diyelim.

                  Bunlara index yapmaya gerek yokmu ?

                  Sadece haber ararkan öyleyse index kullanılacak diye şuan anladım.

                  Burada kafam karıştı son sorum bu olsun 🙂

                  İndex arama yapılan kısımlar için mi kullanılıyor yoksa 20 sütunlu bir verinin 3 parçasını anasayfada veya kategori sayfalarında gösterirken mi index lazım

                  Yani şurası için index gerekmiyor mu? bu gösterdiğim kategori sayfası paginate kullanılarak belkide 500 sayfa içerisinde 10.000 veri olacak ileride diye düşünebiliriz

                  @foreach($haber as $data)
                  <div class="content-entry-wrap dzn-1">
                      <div class="entry-content">
                          <h3 class="entry-title fw-600">
                              <a href="{{$data->url}}">{{$data->baslik}}</a>
                          </h3>
                      </div>
                      <div class="entry-summary">
                          <p>{{$data->ozet}}</p>
                      </div>
                  </div>
                  @endforeach

                  mgsmus teşekkür ederim hocam dediğiniz gibi sayfalarca bilgiyi tek yerde aramaya kalkıyoruz doğru bilgiye ulaşamama yada doğru bilgiyi akılda doğru sentezleyememe korkusundan direk sizlerden bilgi almak çok faydalı oluyor.

                    • mgsmus

                      Seviye 1382
                    • Düzenlendi

                    byhk44 Hayır anlamadınız. Bir tane haberler diye tablonuz olsun:

                    CREATE TABLE news
                    (
                        id         BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                        title      VARCHAR(255)    not null,
                        slug       VARCHAR(255)    not null,
                        content    LONGTEXT        not null
                    );

                    Buraya iki tane index atılacak, biri slug için unique index, diğeri title ve content için full-text (id MySQL'de otomatik olarak PRMARY index olur). Slug benzersiz olması gerektiği için index unique olacak böylece hem aynı slugdan eklenmesini veritabanı düzeyinde engellemiş olacağız hem de WHERE slug = 'haber-basligi' gibi sorgular hızlı çalışacak:

                    CREATE UNIQUE INDEX news_slug_unique_index on news (slug);

                    title ve content alanı için ise full-text index:

                    CREATE FULLTEXT INDEX news_search_index ON news (title, content);

                    Bu indexi kullanabilmek için full-text araması yapılması lazım:

                    SELECT      *,
                                MATCH(title, content) AGAINST('"arama+ kelimesi+"' IN BOOLEAN MODE) as score
                    FROM        news
                    WHERE       MATCH(title, content) AGAINST('"arama+ kelimesi+"' IN BOOLEAN MODE)
                    ORDER BY    score

                    Örneğin şimdi bir LIKE sorgusunu bir de MATCH...AGAINST sorgusunu EXPLAIN ANALYZE ile kontrol edelim:

                    EXPLAIN ANALYZE
                    SELECT  *
                    FROM    news
                    WHERE   title LIKE '%arama kelimesi%' 
                       OR   content LIKE '%arama kelimesi%';
                    EXPLAIN ANALYZE
                    SELECT      *,
                                MATCH(title, content) AGAINST('"arama+ kelimesi+"' IN BOOLEAN MODE) as score
                    FROM        news
                    WHERE       MATCH(title, content) AGAINST('"arama+ kelimesi+"' IN BOOLEAN MODE)
                    ORDER BY    score DESC

                    İlk sorgunun çıktısı:

                    -> Filter: ((news.title like '%arama kelimesi%') or (news.content like '%arama kelimesi%'))  (cost=0.35 rows=1) (actual time=0.016..0.016 rows=0 loops=1)
                        -> Table scan on news  (cost=0.35 rows=1) (actual time=0.015..0.015 rows=0 loops=1)

                    İkinci sorgunun çıktısı

                    -> Sort row IDs: (match news.title,news.content against ('"arama+ kelimesi+"' in boolean mode))  (cost=0.35 rows=1) (actual time=0.009..0.009 rows=0 loops=1)
                        -> Filter: (match news.title,news.content against ('"arama+ kelimesi+"' in boolean mode))  (actual time=0.005..0.005 rows=0 loops=1)
                            -> Indexed full text search on news using news_search_index (title='"arama+ kelimesi+"')  (actual time=0.004..0.004 rows=0 loops=1)

                    İkinci sorguda Indexed full text search on news using news_search_index... şeklindeki bize sorguyu çalıştırırken index kullandığını belirtiyor. İkinci sorguda ise Table scan on news... diyerek index kullanmadığını, tüm tabloyu taradığını belirtiyor. Boş tablo olmasına rağmen ilk sorgunun süresi 0.015 ms iken ikinci sorgunun süresi 0.004 ms yani ilk sorgu ikinci indexli sorgunun 3.75 katı daha yavaş...

                    Primary index, tarihlerde index kullanımı, composite index, partial composite index, B-TREE, B+TREE, HASH... Şimdi anlatabilmiş olmam lazım. Bu konu PHP ya da Laravel ile ilgili bir konu değil...

                      • byhk44

                          Seviye 18
                        • Düzenlendi

                        mgsmus Hocam çok teşekkür ederim iyice karıştı ortalık ama bir şekilde anlayıp uygulamaya çalışacağım elinize emeğinize sağlık.. "İndex arama yapılan kısımlar için mi kullanılıyor yoksa 20 sütunlu bir verinin 3 parçasını anasayfada veya kategori sayfalarında gösterirken mi index lazım" yani tam olarak her veri çekme işlemi aslında bir arama yapmakmıdır? bunun tam olarak cevabı nedir burayıda anlarsam hepsini harmanlayacağım sanırım

                        Bu arada benim hatam tam olarak öğrenmeden bir uygulamaya başlamak oldu, ama muhtemelen birşeyleri denemeden ve uygulamadan öğrenmek çok zor olacaktı. Bu şekilde karışık gitmek daha faydalı gibi geliyor bana

                          byhk44

                          byhk44 Index arama yapılan kısımlar için mi kullanılıyor yoksa 20 sütunlu bir verinin 3 parçasını anasayfada veya kategori sayfalarında gösterirken mi index lazım

                          Index kayıtlara erişirken gerekli, kayıtlara hızlı bir şekilde erişmeniz için. Gösterme dediğiniz işlem kayıtlar çekildikten sonra, PHP ile yapılan bir işlem. O aşamaya geldiğinizde index ile işiniz kalmamış oluyor.

                          Her veri çekme işlemi veritabanı genelinde bir arama/filtreleme işlemidir. SELECT * FROM users yaptığınızda tablolar içinden sadece users tablosundaki kayıtları istiyorsunuz, bu da bir çeşit filtrelemedir ama biz arama/filtreleme derken aslında bir tablo üzerinde yapılan işlemden bahsederiz o yüzden SELECT * FROM users ifadesinde arama/filtreleme yok. Olabilmesi için WHERE, MATCH...AGAINST vs kullanılması gerekiyor, yani filtrelenmesi gerekiyor. Yani kabaca söylemek gerekirse WHERE kullanılan sorguda indexleme yapma ihtiyacınız olabilir. Bu sadece SELECT için değil WHERE kullanılan UPDATE ve DELETE sorguları için de geçerli ama UPDATE ve DELETE kısımlarında işler biraz karışıyor, sadece okuma değil yazma ve silme işlemlerinde de performans söz konusu, o yüzden o kısımları şimdilik düşünmenize gerek yok.

                          Bu anlattıklarım ve etkileri sadece farklı veritabanları için değil aynı veritabanındaki farklı motorlar içinde bile değişiklik gösterebilir. MySQL'de InnoDB ile MyISAM motorlarında indexler farklı depolanır mesela. MySQL'de foreign key için otomatik index oluşturulurken PostgreSQL'de sizin ayrıca oluşturmanız gerekir vs...

                          Index de yer kaplar, gereksiz atılan indexler fazla yer tüketimine ve yavaşlamalara neden olur. Bilinçli yapmanız gerekiyor.

                          Tabloda index kullanılması WHERE kullandığınızda her zaman index kullanılacağı anlamına gelmez. Onu veritabanı motoru belirliyor, sorgu sırasında planlama yapıyor hangisi daha performanslı ise onu kullanıyor. O yüzden EXPLAIN ANALYZE yaptığınızda aynı sorguda farklı kayıt sayılarında index kullanımında farklılıklar görebilirsiniz.

                          Bir tabloda 500-600 binden az kayıt varsa genellikle indexleri düşünmenize gerek kalmıyor, index kullanmadan da hız yeterli olacaktır diye düşünüyorum. Milyonlarla ilgilendiğinizde index önemli oluyor.

                            mgsmus Her şey için teşekkür ederim hocam. Yine mükemmel faydalı olan cevaplar verdiniz. Söyleyecek bir şey bulamıyorum 🙂 iyi çalışmalar dilerim. Bilginize sağlık..