Bir sorgu sırasında diskten ne alınır?


14

Muhtemelen basit bir soru, muhtemelen bir yere cevap verdi, ancak Google için doğru arama sorusunu oluşturamıyorum ...

Belirli bir tablodaki sütun sayısı, o tablonun bir alt kümesinde sorgulama yaparken bir sorgunun performansını etkiler mi?

Örneğin, tablo Foo'nun 20 sütunu varsa, ancak sorgum bu sütunlardan yalnızca 5 tanesini seçiyorsa, 20 (10'a karşı) sütuna sahip olmak sorgu performansını etkiler mi? Basit olması için, WHERE yan tümcesindeki herhangi bir şeyin bu 5 sütuna dahil edildiğini varsayalım.

İşletim sisteminin disk önbelleğine ek olarak Postgres arabellek önbelleğinin kullanımı konusunda endişeliyim. Postgres'in fiziksel depolama tasarımını çok iyi anlayamadım. Tablolar birkaç sayfada saklanır (varsayılan olarak sayfa başına 8k boyutundadır), ancak tupllerin oradan nasıl düzenlendiğini tam olarak anlamıyorum. PG sadece bu 5 sütunu içeren verileri diskten alacak kadar akıllı mı?


50 bayt getirmekten bahsediyorsunuz, ancak kalan 150'den değil. Diskiniz muhtemelen bundan daha büyük artışlarla okuyor!
Andomar

Bu numaraları nereden alıyorsunuz?
Jmoney38

Yanıtlar:


15

Satırlar için fiziksel depolama alanı Veritabanı Sayfa Düzeni'ndeki dokümanlarda açıklanmaktadır . Aynı satırın sütun içeriğinin tümü, TOAST tarafından düzenlenen içerikler (bir sayfaya sığmayacak kadar büyük) dışında, aynı disk sayfasında depolanır . İçerikler, açıklandığı gibi her sıra içinde sırayla çıkarılır:

Verileri okumak için her bir özniteliği sırayla incelemeniz gerekir. İlk olarak, boş bitmap'e göre alanın NULL olup olmadığını kontrol edin. Eğer öyleyse, bir sonrakine git. Ardından doğru hizalamaya sahip olduğunuzdan emin olun. Alan sabit genişlikli bir alansa, tüm baytlar basitçe yerleştirilir.

En basit durumda (TOAST'lu sütun yok), az sayıda sütun gerekse bile postgres tüm satırı getirecektir. Bu durumda, cevap evettir, daha fazla sütuna sahip olmak, özellikle TOAST eşiğinin altındayken sütun içeriği büyükse, atık tamponu önbelleği üzerinde net bir olumsuz etkiye sahip olabilir.

Şimdi TOAST durumu: tek bir alan ~ 2kB'yi aştığında, motor alan içeriğini ayrı bir fiziksel tabloya kaydeder. Ayrıca, tüm satır bir sayfaya sığmadığında da devreye girer (varsayılan olarak 8kB): alanların bazıları TOAST depolama alanına taşınır. Doc diyor ki:

Değişken uzunluklu bir alansa (attlen = -1), o zaman biraz daha karmaşıktır. Tüm değişken uzunluklu veri türleri, depolanan değerin toplam uzunluğunu ve bazı bayrak bitlerini içeren ortak başlık yapısı yapı varlena'yı paylaşır. Bayraklara bağlı olarak, veriler satır içi veya bir TOAST tablosunda olabilir; sıkıştırılmış da olabilir

TOAST içeriği açıkça gerekmediklerinde getirilmez, bu nedenle getirilecek toplam sayfa sayısı üzerindeki etkileri azdır (sütun başına birkaç bayt). Bu, @ dezso'nun cevabındaki sonuçları açıklar.

Yazmaya gelince, tüm sütunları olan her satır, hangi sütunlar değiştirilirse değiştirilsin, her UPDATE'de tamamen yeniden yazılır. Bu nedenle, daha fazla sütuna sahip olmak, yazma işlemleri için daha maliyetlidir.


Bu bir tekme cevap. Tam olarak aradığım şey. Teşekkür ederim.
Jmoney38

1
Ben satır yapısı (pageinspect ve bazı örnek kullanım) açısından bulundu iyi bir kaynak burada .
Jmoney38

10

Daniel'in yanıtı , satırları okuma maliyetine odaklanıyor. Bu bağlamda: Sabit boyutlu NOT NULLsütunları tablonuza ilk sıraya koymak biraz yardımcı olur. Önce alakalı sütunları koymak (sorguladığınız sütunlar) biraz yardımcı olur. Sütunlarınızla hizalama tetrisini oynayarak dolguyu (veri hizalaması nedeniyle) en aza indirmek biraz yardımcı olabilir. Ancak, özellikle büyük tablolar için en önemli etkiden henüz bahsedilmedi.

Ek sütunlar bir satırın daha fazla disk alanını kapladığı açıktır, böylece bir veri sayfasına daha az satır sığar (varsayılan olarak 8 kB). Tek tek satırlar daha fazla sayfaya yayılır. Veritabanı motoru genellikle tek tek satırları değil, tüm sayfaları getirmelidir . Aynı sayıda sayfanın okunması gerektiği sürece münferit satırların biraz daha küçük veya daha büyük olması önemli değildir.

Bir sorgu, büyük bir tablonun (nispeten) küçük bir bölümünü alırsa, burada satırlar bir dizin tarafından desteklenen tüm tabloya rasgele yayılırsa, bu, çok az dikkate alınarak kabaca aynı sayıda sayfa okumasına neden olur. satır boyutuna. Alakasız sütunlar, bu tür (nadir) bir durumda sizi yavaşlatmaz.

Genellikle, sırayla veya yakınlık olarak girilen satırların yamalarını veya kümelerini alır ve veri sayfalarını paylaşırsınız. Bu satırlar dağınıklık nedeniyle yayılır, sorgunuzu tatmin etmek için daha fazla disk sayfası okunmalıdır. Daha fazla sayfa okumak zorunda kalmak genellikle bir sorgunun daha yavaş olmasının en önemli nedenidir . Alakasız sütunların sorgularınızı yavaşlatmasının en önemli faktörü budur.

Büyük veritabanlarında, genellikle hepsini önbellekte tutmak için yeterli RAM yoktur. Daha büyük satırlar daha fazla önbellek, daha fazla çekişme, daha az önbellek isabet, daha fazla disk G / Ç kaplar. Disk okumaları genellikle çok daha pahalıdır. SSD'ler için daha az, ancak önemli bir fark var. Bu, sayfa okumaları hakkında yukarıdaki noktaya katkıda bulunur.

Bu olabilir veya olmayabilir alakasız sütunlar TOST-ed iseniz fark. İlgili sütunlar da TOAST ile düzenlenebilir ve aynı etkinin çoğunu geri getirir.


1

Küçük bir test:

CREATE TABLE test2 (
    id serial PRIMARY KEY,
    num integer,
    short_text varchar(32),
    longer_text varchar(1000),
    long_long_text text
);

INSERT INTO test2 (num, short_text, longer_text, long_long_text)
SELECT i, lpad('', 32, 'abcdefeghji'), lpad('', 1000, 'abcdefeghji'), lpad('', (random() * 10000)::integer, 'abcdefeghji')
FROM generate_series(1, 10000) a(i);

ANALYZE test2;

SELECT * FROM test2;
[...]
Time: 1091.331 ms

SELECT num FROM test2;
[...]
Time: 21.310 ms

Sorguyu ilk 250 satıra ( WHERE num <= 250) sınırlamak, sırasıyla 34.539 ms ve 8.343 ms'dir. long_long_textBu sınırlı set dışında tümünü seçmek 18.432 ms'de sonuçlanır. Bu, terimlerinize göre PG'nin yeterince akıllı olduğunu gösterir.


Girdi için kesinlikle minnettarım. Ancak, bu test senaryosunun aslında önerdiğimi kanıtladığını kesin olarak söyleyemem. Birkaç sorun var. Birincisi, "SELECT * FROM test2" yi ilk çalıştırdığınızda, paylaşılan arabellek önbelleğinizi doldurmuş olması gerekir. Bu sorgunun diskten alınması çok daha uzun sürecekti. Böylece, 2. sorgu teorik olarak çok daha hızlı olurdu çünkü SB önbelleğinden getirilirdi. Ancak, PG'nin daha sonraki testlerinize / karşılaştırmalarınıza dayanarak yalnızca ihtiyaç duyduğu satırları getirmesini 'önerdiğini' kabul ediyorum.
Jmoney38

Haklısın, bu testin (basit olmak) kusurları var. Yeterli zamanım olursa bunları da ele almaya çalışacağım.
dezso
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.