Onlara kullanıcı erişimini kesmeden büyük DB tablolardan aylık yenileme yapmak için nasıl

10 Cevap php

Ben yeniden yazılması / her hafta veya her ay yenilenir gereken bir Oracle veritabanında dört DB tablolar var. Ben standart OCI fonksiyonlarını kullanarak PHP bu senaryoyu yazıyorum, o XML yeni veri okumak ve bu dört tabloları yenilenir. Dört tablo, aşağıdaki özelliklere sahiptir

TABLO A - satırları 2mil kadar, bir birincil anahtar (bir satır max 2K verileri alabilir)

TABLO B - 10mil satır kadar, TABLO A bir yabancı anahtar işaretleme (Bir satır veri maksimum 1100 bayt sürebilir)

TABLO C - 10mil satır, TABLO A bir yabancı anahtar işaret kadar (Bir satır veri maksimum 1100 bayt sürebilir)

TABLO D - 10mil satır kadar, TABLO A bir yabancı anahtar işaretleme (Bir satır veri max 120 bayt sürebilir)

Yani kullanıcı deneyimini zarar vermeden bu tabloları yeniden doldurmanız gerekir. Açıkçası tabloları silemezsiniz ve biraz uzun bir süreç olarak sadece onları yeniden doldurmak.

Ben tüm tabloları silin ve sadece onları yeniden koca bir işlem kabul ettik. Ben işlemin uzunluğu konusunda biraz endişe olsun (henüz bilmiyorum ama bir saat ya da öylesine sürebilir).

Ben bütün tabloların geçici tablo kopyaları oluşturmak ve o yerine doldurmak istedim. Sonra ana tablo DAMLA ve geçici tablolar yeniden adlandırabilirsiniz. Eğer DAMLA yapmak ve onlar her zaman işlemek bir otomobil yapmak gibi bir işlem içinde tablo ALTER ifadeler olamaz ancak. Bu (dört BIRAKMA ve ve dört ALTER TABLE deyimleri) hızlı bir şekilde yapılabilir, ama bir kullanıcı zaman kısa süre içinde bir hata almazsınız garanti edemez gerekir.

Şimdi, iki fikirlerin bir arada, ben o ana tabloları yeniden doldurmak için dört orijinal tabloları DAN delete yapıyor ve sonra ve INSERT INTO geçici tablolar, geçici tablolar yapıyorum düşünüyorum. Burada DDL deyimleri vardır beri, bu tüm bir işlem içinde çalışacak. Daha sonra, ancak bir işlem içinde 60 milyon kayıtları işlemek için gereken bellek (bu da ilk fikir için bir endişe olurdu) belaya gidiyor diye merak.

Ben bu ortak bir senaryo olacağını düşünürdüm. Bunu yapmanın bir standart ya da önerilen bir yolu var mı? Herhangi bir ipucu mutluluk duyacağız. Teşekkürler.

10 Cevap

Kim ilk test the simplest possible solution, yani daha gelişmiş bir şey inşa etmek denemeden önce, / INSERT, DELETE olurdu (Vincent hariç) tek ben miyim?

Daha sonra, ancak bir işlem içinde 60 milyon kayıtları işlemek için gereken bellek (bu da ilk fikir için bir endişe olurdu) belaya gidiyor diye merak.

Oracle oldukça iyi belleği yönetir, o (ayyy sadece ağzımdan çıktı!) Java acemiler bir grup tarafından yazılmış değil. Yani asıl soru, diğer bir deyişle, bir performans test durumda inşa ve sunucu üzerinde çalışan ve bu kadar uzun sürdüğünü görmek ... dayak yinele performans cezalar endişe ve log dosyaları GERİ zorunda edilmektedir. DELETE sırasında / sistem her zamanki gibi duyarlı olmayacaktır INSERT ancak diğer oturumları hala kilitlenmeler, bellek sızıntıları veya sistem çökmelerine hiçbir korkuları olmadan seçer gerçekleştirebilirsiniz. İpucu: DB sunucuları genellikle disk bağlı, bu yüzden uygun bir RAID dizisi almak genellikle çok iyi bir yatırımdır.

Performans kritik eğer Öte yandan, bu parçacığı açıklanan alternatif yaklaşımlardan birini seçebilirsiniz:

  • bölümleme lisans varsa
  • tablo bunu yapmazsanız yeniden adlandırma, ama anında DDLs gibi bir nesne hükümsüzlük, ORA-06508 gibi bazı yan etkilere neden olabilir dikkatli olmak ...

Eğer büyük tablolarının her biri için bir eşanlamlı olabilir. Sofranıza yeni enkarnasyonlarını oluşturun, onları doldurmak bırakın ve eş anlamlı yeniden, ve nihayet eski tabloları bırakın. Bu (1) DML'nin tek gerçek set (ekler) ve silmeleri için kokan kaçınarak nesil ve (2) eşanlamlısı damla / Recreate çok hızlı, bir "kötü bir kullanıcı deneyimi" için potansiyeli en aza indirmek avantajı vardır.

Oracle'ın eş hakkında benim küçük huysuzlaştırmak hatırlatıyor: neden bir ALTER SYNONYM komut var değil mi?

Ben her hafta başka bir kaynaktan silinir beri kullanıcılar aslında bu tablolardaki verileri değiştirmek yok farz ediyorum, bu yüzden tam bir saat boyunca masaları kilit eğer gerçekten önemli değil. Kullanıcılar hala veri sorgulayabilir, sadece boyut Eğer uygun bir segment geri alma var. Bu nedenle INSERT + basit bir DELETE iyi çalışması gerekir.

Bir şeyler AND hızlandırmak istiyorsanız yeni veri bir önceki veri ile küçük bir fark varsa Şimdi geçici tablolar içine yeni veri yüklemek ve bir ile delta ile tabloları güncellenmesi olabilir : MERGE+DELETE böyle kombinasyonu

Kurulum:

CREATE TABLE a (ID NUMBER PRIMARY KEY, a_data CHAR(200));
CREATE GLOBAL TEMPORARY TABLE temp_a (
   ID NUMBER PRIMARY KEY, a_data CHAR(200)
) ON COMMIT PRESERVE ROWS;
-- Load A
INSERT INTO a 
   (SELECT ROWNUM, to_char(ROWNUM) FROM dual CONNECT BY LEVEL <= 10000);
-- Load TEMP_A with extra rows
INSERT INTO temp_a 
   (SELECT ROWNUM + 100, to_char(ROWNUM + 100) 
      FROM dual 
   CONNECT BY LEVEL <= 10000);
UPDATE temp_a SET a_data = 'x' WHERE mod(ID, 1000) = 0;

Bu MERGE deyimi yeni bir satır eklemek ve bunlar farklı sadece eski satırları güncellenir:

SQL> MERGE INTO a
  2  USING (SELECT temp_a.id, temp_a.a_data
  3           FROM temp_a
  4           LEFT JOIN a ON (temp_a.id = a.id)
  5          WHERE decode(a.a_data, temp_a.a_data, 1) IS NULL) temp_a
  6  ON (a.id = temp_a.id)
  7  WHEN MATCHED THEN
  8     UPDATE SET a.a_data = temp_a.a_data
  9  WHEN NOT MATCHED THEN
 10     INSERT (id, a_data) VALUES (temp_a.id, temp_a.a_data);

Done

Daha sonra verilerin yeni kümesinde olmayan satırları silmek gerekir:

SQL> DELETE FROM a WHERE a.id NOT IN (SELECT temp_a.id FROM temp_a);

100 rows deleted

Sen çocuk tabloları içine sonra takın ve ters sırayla silme olacaktır.

Oracle senin bir tarihi veya saati sütunu sadece yerine bir silme komutu yerine bölümü bırakabilirsiniz birçok veri kaldırmak için bu şekilde dayalı tablolar ve indeksler bölümlere ayırabilirsiniz.

Biz 100 Milyon + kayıtları aylık arşivleri yönetmek için kullanabilirsiniz ve kesinti yok etmek için kullanılır.

http://www.oracle.com/technology/oramag/oracle/06-sep/o56partition.html bölümleme hakkında öğrenme için süper kullanışlı bir sayfasıdır.

Sana yük sırasında diğer yazma süreçleri nedeniyle tutarsızlıkları hakkında endişelenmenize gerek yok ki, bu ferahlatıcı faaliyet, veriler bu tablolarda değişen tek yolu olduğunu varsayalım.

Tüm bu silme ve yerleştirme geri alma kullanım açısından maliyetli olacaktır; Ayrıca daha hızlı veri yükleme teknikleri kullanarak seçeneği dışlar. Örneğin, ekler yük yapıldıktan sonra indeksler uygulayın, sonra çok daha hızlı bir dizin ile tabloya eklerseniz, daha gidecek. Orada başka stratejiler de vardır, ama her ikisi de "bir işlem yapmak o tüm" teknik engel.

Sizin ikinci seçim benim seçimim olurdu - eski tabloları bırakın, sonra, yeni tablolar oluşturmak daha sonra bir kukla adı eskileri yeniden adlandırmak, yeni adıyla temps yeniden adlandırın. Renames hızlı olduğundan, masalar kullanılamaz iken bir saniyeden daha kısa bir pencere olurdu, ve daha sonra rahatca eski tabloları damla serbest olurdu.

Bu bir ikinci pencere kabul edilemez ise, bu gibi durumlarda kullanmış olduğunuz bir yöntemdir ek kilitleme nesnesi kullanmaktır - kullanıcılar gerçek tablolar erişmek önce seçmek için gerekli olacağını bir tek satır ile özellikle, bir masa ve onu yeniden adlandırma işlemi yapar önce yükleme işlemi özel modda kilit olabilir.

PHP komut db iki bağlantı kullanmak - Eğer kilidi yapmak birini, sen yükleme nerede yapılacak diğer, yeniden adlandırma ve düşüyor. Örtülü iş bağlantısı taahhüt Bu şekilde diğer tablodaki kilit sonlandırılacak.

Yani, komut, gibi bir şey yapmak istiyorum:

Connection 1: Create temp tables, load them, create new indexes

Bağlantı 2:

LOCK TABLE Load_Locker IN SHARE ROW EXCLUSIVE MODE;

Connection 1: Perform renaming swap of old & new tables

Bağlantı 2: Rollback;

Connection 1: Drop old tables.

Bu arada, müşterilerine hemen bir işlem (veya seçtiği bir dizi) başladıktan sonra aşağıdaki komutu olacaktır:

LOCK TABLE Load_Locker IN SHARE MODE;

Sen tablo bu şekilde kilitleme gibi birçok müşterimiz var olabilir - hepsi kilit serbest kadar yukarıdaki süreç size işlemleri gerçekleştirmek kadar, izleyen müşteriler engeller hangi noktada, arkalarında engeller. Eğer SHARE ROW EXCLUSIVE kilit bağlam içinde yapıyoruz tek şey tabloları yeniden adlandırma olduğundan, müşterileriniz sadece hiç bir an için bloke olur. Ayrıca, ayrıntı bu seviyede koyarak Eğer istemcilerin eski tablonun salt tutarlı bir görünüm olurdu ne kadar kontrol etmenizi sağlar; Biraz zaman aldı okur bir dizi yaptım bir müşteri olsaydı o olmadan, size tabloları orta dere değişen sonunda olabilir ve erken sorguları eski verileri & çekti eğer garip sonuçlar ile rüzgar Daha sonra sorguları yeni veri çekti. SADECE OKUYUN SET HAREKET SET yalıtım düzeyi kullanarak benim yaklaşım kullanarak değil, bu sorunu ele başka bir yolu olacaktır.

Bu yaklaşımın tek gerçek dezavantajı istemci okuma işlemleri biraz zaman alabilir, siz, bir an daha uzun süre engellenen diğer müşterilerinin riskiyle olduğunu, yükleme işlemi ÖZEL onun SHARE ROW yayınladıktan sonra meydana SHARE MODE herhangi kilitleri beri yükleme işlemi görevini bitirinceye kadar kilit engeller. Örneğin:

10:00 user 1 issues SHARE lock
10:01 user 2 issues SHARE lock
10:03 load process issues SHARE ROW EXCLUSIVE lock (and is blocked)
10:04 user 3 issues SHARE lock (and is blocked by load's lock)
10:10 user 1 releases SHARE
10:11 user 2 releases SHARE (and unblocks loader)
10:11 loader renames tables & releases SHARE ROW EXCLUSIVE (and releases user 3)
10:11 user 3 commences queries, after being blocked for 7 minutes

Ancak, bu gerçekten oldukça kıytırık olduğunu. Bölümleme Kinlan çözümü büyük olasılıkla gitmek için yoludur. Bir sürüm numarasını içeren kaynak tablolar ekstra bir sütun ekleyin, o sürüme dayalı veri bölümlemek, sonra sadece bir bir satırın değeri tarafından belirlenen mevcut sürümü (gösterir verileri göstermek mevcut tabloları benziyorsun görünümler oluşturmak "CurrentVersion" tablosu). Sonra sadece, tabloya yük do CurrentVersion tablosunu güncelleştirmek, ve eski veri bölümü bırakın.

Neden sürüm sütun eklemek değil mi? Eğer farklı bir sürüm numarasına sahip yeni bir satır ekleyebilirsiniz yolu. Geçerli sürümünü belirten tabloya karşı bir görünüm oluşturun. Yeni satırlar yeni sürüm numarasına sahip görüntüsü derleyişinizde eklendikten sonra. O bitti, geri dönün ve eski satırları silin.

"Ben benim seçin tabloların her bir yerde version = 1 tümce eklemek zorunda fikri ile bir küçük kapalı değilim."

(A) Daha da kötüsü, muhtemelen emin olmak istiyorum 'burada version = Currentversion select versiyonu' ya da böyle.

(B) Ama sen var seçmek her bu koşulu eklemek zorunda değilsiniz. Böyle STORED_TABLEA gibi isimler ile tablolar "özel" yapmak, ve gibi Defa (kabaca) SELECT * STORED_TABLEA WHERE VERSION = CURRENTVERSION "" "OLARAK GÖRÜNTÜSÜ Table_A CREATE". Belki CURRENTVERSION güncellenen aldığında görünümü sağ cursoring birisi ne olduğu hakkında akla sahip olmalıdır.

Ve tabii bu tür sorunlara gerçek doğru çözümü her zaman vardır: (kalıcı veri depolamak için) kendi amacı için veritabanını kullanın ve XML hendek.

Ne bazı durumlarda yapılacak tablolar iki versiyonu var olduğunu, SalesTargets1 ve SalesTargets2 (aktif ve inaktif bir.) Inaktif birinden kayıtları kesecek ve bunu doldurmak demek. Hiç kimse ama inaktif birini kullanır beri doldurma iken, hiçbir kilitleme sorunları veya kullanıcılar üzerindeki etkisi olmalıdır. Sonra aktif tablosundan tüm bilgilerin selcts görünümü var (o anki tablo şimdi ne isim verilmelidir, benim örnekte SalesTargets söylüyorlar). Sonra yenilenen veri geçmek için, yapmanız gereken bütün bir alter görünümü deyimi çalıştırılır.

Eğer (değişikliklerin) delta boyutunu değerlendirdik.

(Takılı karşıt olarak) Eğer çok yüksek değil, yeni bir satır kümesi yukarı koymak her zaman güncel olsun satır sayısını, sonra düşünüyorum Eğer evreleme tablo bir dizi içine veri yeni dizi ithal düşünün ve yapmanız gereken bir güncelleme- -olmadığı durumlarda ve (Upsert) çözümü nerede-var olmayan-takın ve sadece (Tamam endeksler ok) ve indeksleri yenileyin.

ETL gibi davranın.

Ben burada bir Upsert yöntemi ile gidiyorum.

I tabloların her biri için ek bir "sil" sütunu ilave edildi.

Ben yem işleme başladığınızda, ben '1 her kayıt için 'delete alanını ayarlayın.

Eğer bu olmuyorsa o zaman ben kayıt varsa güncellemeleri ya da ekler ciddi geçmesi. Bu ekler / güncellemeleri her biri için, silme alan daha sonra sıfıra ayarlanır.

Sürecin sonunda hala ''1 silme değerine sahip tüm kayıtları silin.

Teşekkürler cevaplar için herkes. Ben eğitim / çok ilginç buldum.