Time_stamp, usr_id, transaction_id ve life_remaining için sütunlara sahip kayıtları içeren bir Postgres tablosu ("yaşamlar" olarak adlandırılır) ile uğraşıyorum. Her usr_id için bana en son yaşamları geri kalan toplamı verecek bir sorguya ihtiyacım var
- Birden fazla kullanıcı var (farklı usr_id'ler)
- time_stamp benzersiz bir tanımlayıcı değildir: bazen kullanıcı olayları (tabloda tek tek) aynı time_stamp ile gerçekleşir.
- trans_id yalnızca çok küçük zaman aralıkları için benzersizdir: zamanla tekrar eder
- Kalan_ yaşamlar (belirli bir kullanıcı için) zaman içinde hem artabilir hem de azalabilir
misal:
time_stamp | lives_remaining | usr_id | trans_id ----------------------------------------- 07:00 | 1 | 1 | 1 09:00 | 4 | 2 | 2 10:00 | 2 | 3 | 3 10:00 | 1 | 2 | 4 11:00 | 4 | 1 | 5 11:00 | 3 | 1 | 6 13:00 | 3 | 3 | 1
Verilen her usr_id için en son verileri içeren satırın diğer sütunlarına erişmem gerekeceğinden, şöyle bir sonuç veren bir sorguya ihtiyacım var:
time_stamp | lives_remaining | usr_id | trans_id ----------------------------------------- 11:00 | 3 | 1 | 6 10:00 | 1 | 2 | 4 13:00 | 3 | 3 | 1
Belirtildiği gibi, her usr_id can kazanabilir veya kaybedebilir ve bazen bu zaman damgalı olaylar, aynı zaman damgasına sahip olacak kadar birbirine çok yakın gerçekleşir! Bu nedenle bu sorgu çalışmayacaktır:
SELECT b.time_stamp,b.lives_remaining,b.usr_id,b.trans_id FROM
(SELECT usr_id, max(time_stamp) AS max_timestamp
FROM lives GROUP BY usr_id ORDER BY usr_id) a
JOIN lives b ON a.max_timestamp = b.time_stamp
Bunun yerine, doğru satırı belirlemek için hem time_stamp (birinci) hem de trans_id (saniye) kullanmam gerekiyor. Daha sonra bu bilgiyi alt sorgudan, uygun satırların diğer sütunları için veri sağlayacak olan ana sorguya aktarmam gerekiyor. Bu, çalışmak zorunda olduğum saldırıya uğramış sorgu:
SELECT b.time_stamp,b.lives_remaining,b.usr_id,b.trans_id FROM
(SELECT usr_id, max(time_stamp || '*' || trans_id)
AS max_timestamp_transid
FROM lives GROUP BY usr_id ORDER BY usr_id) a
JOIN lives b ON a.max_timestamp_transid = b.time_stamp || '*' || b.trans_id
ORDER BY b.usr_id
Tamam, bu işe yarıyor ama hoşuma gitmiyor. Sorgu içinde bir sorgu, kendi kendine birleştirme gerektirir ve bana öyle geliyor ki, MAX'ın en büyük zaman damgasına ve trans_id'ye sahip olduğunu bulduğu satırı yakalayarak çok daha basit olabilir. "Yaşıyor" tablosunun ayrıştırılması gereken on milyonlarca satırı var, bu nedenle bu sorgunun olabildiğince hızlı ve verimli olmasını istiyorum. Özellikle RDBM ve Postgres konusunda yeniyim, bu nedenle uygun dizinleri etkili bir şekilde kullanmam gerektiğini biliyorum. Nasıl optimize edeceğim konusunda biraz kayboldum.
Burada benzer bir tartışma buldum . Oracle analitik işlevine eşdeğer bir tür Postgres gerçekleştirebilir miyim?
Bir toplama işlevi (MAX gibi) tarafından kullanılan ilgili sütun bilgilerine erişme, dizinler oluşturma ve daha iyi sorgular oluşturma konusunda herhangi bir tavsiye çok takdir edilecektir!
Not: Örnek vakamı oluşturmak için aşağıdakileri kullanabilirsiniz:
create TABLE lives (time_stamp timestamp, lives_remaining integer,
usr_id integer, trans_id integer);
insert into lives values ('2000-01-01 07:00', 1, 1, 1);
insert into lives values ('2000-01-01 09:00', 4, 2, 2);
insert into lives values ('2000-01-01 10:00', 2, 3, 3);
insert into lives values ('2000-01-01 10:00', 1, 2, 4);
insert into lives values ('2000-01-01 11:00', 4, 1, 5);
insert into lives values ('2000-01-01 11:00', 3, 1, 6);
insert into lives values ('2000-01-01 13:00', 3, 3, 1);