PostgreSQL'de satır olup olmadığını en hızlı kontrol etme


177

Tabloya eklemek için gereken satırlar bir grup var, ama bu ekler her zaman toplu olarak yapılır. Bu yüzden toplu işten tek bir satır olup olmadığını kontrol etmek istiyorum çünkü o zaman hepsinin eklendiğini biliyorum.

Yani birincil anahtar kontrolü değil, ama çok da önemli değil. Ben sadece tek satır kontrol etmek istiyorum, bu yüzden count(*)muhtemelen iyi değil, bu yüzden existssanırım onun gibi bir şey .

Ama PostgreSQL için oldukça yeni olduğum için bilen insanlara sormayı tercih ederim.

Toplu işim aşağıdaki yapıya sahip satırlar içeriyor:

userid | rightid | remaining_count

Tablonun sağlandığı herhangi bir satır içermesi, useridhepsinin orada bulunduğu anlamına gelir.


Tablonun HERHANGİ BİR satır veya toplu işinizden herhangi bir satır olup olmadığını görmek ister misiniz?
JNK

toplu işimdeki herhangi bir satır evet. all share same field ill düzenlemek biraz.
Valentin Kuzub

Lütfen sorunuzu netleştirin. Toplu kayıtlar eklemek ister misin, hepsi ya da hiçbir şey? Kont ile ilgili özel bir şey var mı? (BTW, sütun adı olarak pratik olmayan ayrılmış bir kelime)
wildplasser

tamam, gerçek durumu biraz basitleştirmeye çalışıyordum ama gerçek uygulamaya daha da yakınlaşıyoruz. Bu satırlar eklendikten sonra (belirli bir alan_tarihi için) Belirli hakları kullandıkları için belirtilen kullanıcı için hakları azaltmaya başlıyorum, haklar 0 olduktan sonra artık bu işlemleri o tarih için gerçekleştiremezler. gerçek hikaye
Valentin Kuzub

1
Sadece tablo tanımlarını (ilgili kısmını) gösterin ve ne yapmak istediğinizi söyleyin.
wildplasser

Yanıtlar:


345

DOĞRU / YANLIŞ dönüş için EXISTS anahtar sözcüğünü kullanın:

select exists(select 1 from contact where id=12)

21
Bunun üzerine uzantı, kolay başvuru için döndürülen sütunu adlandırabilirsiniz. Örneğinselect exists(select 1 from contact where id=12) AS "exists"
Rowan

3
Bu daha iyidir, çünkü bazen Hiçbiri (programlama dilinize bağlı olarak) yerine her zaman beklediğiniz şekilde genişlemeyebilecek bir değer (doğru veya yanlış) döndürür.
isaaclw

1
Bu yöntemi kullanarak Seq Scan var. Yanlış birşey yapıyorum?
FiftiN

2
@ Michael.MI 30 milyon satırlı DB tablo var ve kullandığımda existsveya limit 1güçlü performans düşüşü var çünkü Postgres Dizin Tarama yerine Seq Scan kullanıyor. Ve analyzeyardım etmiyor.
FiftiN

2
@maciek lütfen 'id' ifadesinin birincil anahtar olduğunu anlayın, bu nedenle bu kimliğe sahip tek bir kayıt olduğundan “LIMIT 1” anlamsız olurdu
StartupGuy

34

Basitçe:

select 1 from tbl where userid = 123 limit 1;

nerede 123 olduğunuz grubun kullanıcı kimliği .

Yukarıdaki sorgu, belirtilen kullanıcı kimliğine sahip kayıtların olup olmamasına bağlı olarak boş bir küme veya tek bir satır döndürür.

Bu çok yavaş çıkıyorsa, üzerinde bir dizin oluşturmaya bakabilirsiniz tbl.userid.

tablodaki toplu işten tek bir satır bile varsa, bu durumda satırları eklemek zorunda değilim çünkü hepsinin eklendiğinden eminim.

Programınız toplu iş ortasında kesintiye uğramış olsa bile doğru kalması için veritabanı işlemlerini uygun şekilde yönettiğinizden emin olmanızı öneririm (tüm toplu iş tek bir işlemde eklenir).


11
Her zaman 0 veya 1 sayım (*) değerine sahip bir satır döndürmeyi garanti ettiği için "sayım (*) 'dan (1 seçin ... 1 sınır") "seçmek programlı olarak daha kolay olabilir.
David Aldridge

@DavidAldridge sayısı (*) yine de tüm satırların okunması gerektiği anlamına gelirken, 1. kayıt ilk kayıtta durur ve geri döner
Imraan

3
@Imraan Sanırım sorguyu yanlış yorumladın. En fazla 1 satıra sahip COUNTbir yuva üzerinde işlem yapar SELECT( LIMITalt sorguda olduğu için).
jpmc26

9
INSERT INTO target( userid, rightid, count )
  SELECT userid, rightid, count 
  FROM batch
  WHERE NOT EXISTS (
    SELECT * FROM target t2, batch b2
    WHERE t2.userid = b2.userid
    -- ... other keyfields ...
    )       
    ;

BTW: yinelenen bir durumda tüm toplu işin başarısız olmasını istiyorsanız, (birincil anahtar kısıtlaması verildiğinde)

INSERT INTO target( userid, rightid, count )
SELECT userid, rightid, count 
FROM batch
    ;

tam olarak istediğinizi yapar: ya başarılı olur ya da başarısız olur.


Bu, her satırı kontrol edecektir. Tek bir çek yapmak istiyor.
JNK

1
Hayır, tek bir kontrol yapar. Alt sorgu ilişkisizdir. Eşleşen bir çift bulunduğunda kurtarılacaktır.
wildplasser

Doğru, dış sorguya atıfta bulunduğunu düşündüm. +1 size
JNK

BTW: Sorgu bir işlemin içinde olduğundan, yinelenen bir kimlik eklenirse hiçbir şey olmaz, bu nedenle alt sorgu atlanabilir.
vahşi sınıf

hmm anladığımdan emin değilim. Haklar eklendikten sonra sayım sütununu azaltmaya başlarım. (resim için sadece bazı detaylar) Satırlar zaten mevcutsa ve alt sorgu atlanmışsa, yinelenen benzersiz anahtar ile hatalar alıyorum veya? (benzersiz anahtardan kullanıcı kimliği ve doğru form)
Valentin Kuzub

1
select true from tablename where condition limit 1;

Bu postgres yabancı anahtarları kontrol etmek için kullandığı sorgu olduğuna inanıyorum.

Sizin durumunuzda, bunu tek seferde de yapabilirsiniz:

insert into yourtable select $userid, $rightid, $count where not (select true from yourtable where userid = $userid limit 1);

1

@MikeM'in işaret ettiği gibi.

select exists(select 1 from contact where id=12)

ile endeks temas, genellikle 1 ms zaman maliyetini düşürebilir.

CREATE INDEX index_contact on contact(id);

0
SELECT 1 FROM user_right where userid = ? LIMIT 1

Sonuç kümeniz bir satır içeriyorsa, eklemeniz gerekmez. Aksi takdirde kayıtlarınızı ekleyin.


Eğer grup 100 satır içeriyorsa, bana 100 satır dönecektir, iyi olduğunu mu düşünüyorsun?
Valentin Kuzub

1 satıra sınırlayabilirsiniz. Daha iyi performans göstermelidir. Bunun için @aix'ten düzenlenen yanıta bir göz atın.
Fabian Barney

0

Performansı düşünüyorsanız, "PERFORM" u aşağıdaki gibi bir işlevde kullanabilirsiniz:

 PERFORM 1 FROM skytf.test_2 WHERE id=i LIMIT 1;
  IF FOUND THEN
      RAISE NOTICE ' found record id=%', i;  
  ELSE
      RAISE NOTICE ' not found record id=%', i;  
 END IF;

benimle çalışmıyor:
Simon

1
Bu SQL değil pl / pgsql, bu nedenle SQL olarak çalıştırmaya çalışıyorsanız "PERFORM" sözdizimi hatası
Mark K Cowan

-1

Özellikle Cezanı ele almak başka bir düşünce önermek istiyorum: "Ben çünkü partiden tek bir satır tabloda varsa kontrol etmek istiyorum Yani hepsi biliyor ardından edildi takılı ."

"Gruplar" içine yerleştirerek işleri verimli hale getiriyorsunuz, ancak varlığını kontrol etmek her seferinde bir kayıt mı? Bu bana karşı sezgisel görünüyor. Yani " ekler her zaman toplu olarak yapılır " derken, bir insert deyimiyle birden çok kayıt eklediğiniz anlamına gelir . Postgres'in ASİT ile uyumlu olduğunu bilmeniz gerekir. Bir insert deyimiyle birden çok kayıt (bir grup veri) ekliyorsanız , bazılarının eklenip eklenmediğini kontrol etmeye gerek yoktur. İfade ya geçer ya da başarısız olur. Tüm kayıtlar eklenecek veya eklenmeyecek.

Öte yandan, C # kodunuz basitçe bir "set" ayrı ekleme deyimi yapıyorsa, örneğin, bir döngü içinde ve aklınızda, bu bir "toplu iş" .. o zaman aslında " ". "Parti" olarak adlandırdığınız şeyin bir kısmının eklenmeyeceğini beklediğiniz ve aslında bir kontrole ihtiyaç duyduğunuzu düşünmeniz, bu durumda daha temel bir sorununuz olduğunu güçlü bir şekilde göstermektedir. Tek bir eklemeyle birden çok kayıt eklemek için paradigmanızı değiştirmeniz ve tek tek kayıtların yapılıp yapılmadığını kontrol etmeye devam etmeniz gerekir.

Bu örneği düşünün:

CREATE TABLE temp_test (
    id SERIAL PRIMARY KEY,
    sometext TEXT,
    userid INT,
    somethingtomakeitfail INT unique
)
-- insert a batch of 3 rows
;;
INSERT INTO temp_test (sometext, userid, somethingtomakeitfail) VALUES
('foo', 1, 1),
('bar', 2, 2),
('baz', 3, 3)
;;
-- inspect the data of what we inserted
SELECT * FROM temp_test
;;
-- this entire statement will fail .. no need to check which one made it
INSERT INTO temp_test (sometext, userid, somethingtomakeitfail) VALUES
('foo', 2, 4),
('bar', 2, 5),
('baz', 3, 3)  -- <<--(deliberately simulate a failure)
;;
-- check it ... everything is the same from the last successful insert ..
-- no need to check which records from the 2nd insert may have made it in
SELECT * FROM temp_test

Bu aslında herhangi bir ACID uyumlu DB için paradigma .. sadece Postgresql değil. Başka bir deyişle, "toplu" kavramınızı düzeltir ve ilk etapta herhangi bir satır kontrol yapmak zorunda kalmazsanız daha iyi olursunuz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.