İndeksler: düğüm sayısı aynı ise tamsayıya karşı dize performansı


26

Ruby on Rails'de PostgreSQL (9.4) veritabanı ile bir uygulama geliştiriyorum. Kullanım durumum için, uygulamanın bütün noktası bir model üzerinde çok özel özellikler ararken, tablolardaki sütunlar çok sık aranacaktır.

Şu anda sütunlarda bir integertür kullanılıp kullanılmayacağına veya sütunlar için tipik bir dize türünün (örneğin character varying(255), Rails'teki varsayılan ) kullanılmasına karar veriyorum, çünkü performans farkının dizinde ne olacağından emin değilim.

Bu sütunlar enums . Olabilecekleri değerlerin miktarı için sabit bir boyuta sahiptirler. Çoğu enum uzunluğu 5'i geçmez, yani endeks uygulamanın kullanım ömrü boyunca az ya da çok sabitlenir ; Bu nedenle, tamsayı ve dize dizinleri düğüm sayısında aynı olacaktır.

Bununla birlikte, indekslenecek olan dize yaklaşık 20 karakter uzunluğunda olabilir, bellekte kabaca tamsayının 5 katıdır (eğer bir tamsayı 4 byte ise ve dizeler karakter başına 1 byte saf ASCII ise, bu tutar). Veritabanı motorlarının dizin aramalarını nasıl yaptığını bilmiyorum, ancak dizeyi tam olarak eşleşene kadar "taraması" gerekiyorsa , bu durumda, dize aramasının tamsayı aramasından 5 kat daha yavaş olacağı anlamına gelir; tamsayı araması için eşleşene kadar "tarama" 20 yerine 4 bayt olur. Bu, hayal ettiğim şey:

Arama değeri (tamsayı) 4:

tarama ........................… kayıtları alınıyor ... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... |

Arama değeri (string) "some_val" (8 bayt):

tarama................................................. .................................. .. kayıtları alınıyor ... | BYTE_1 | BYTE_2 | BYTE_3 | BYTE_4 | BYTE_5 | BYTE_6 | BYTE_7 | BYTE_8 | ... |

Umarım bu mantıklı geliyor. Temel olarak, tam sayı daha az yer kapladığından, dize eşdeğerinden daha hızlı "eşleştirilebilir". Belki de bu tamamen yanlış bir tahmin, ama ben uzman değilim, bu yüzden size soruyorum. Sanırım az önce bulduğum bu cevap hipotezimi destekliyor gibi görünüyor, ama emin olmak istiyorum.

Sütundaki olası değerlerin sayısı ikisinde de değişmez, bu nedenle dizinin kendisi değişmez (enum'a yeni bir değer eklemediğim sürece). Bu durumda, integerya da varchar(255), ya da bir tamsayı türünü kullanmanın bir anlamı var mıdır?


Sormamın sebebi Rails'in enumtipinin tamsayıları dize tuşlarıyla eşleştirmesidir, ancak kullanıcının karşı karşıya oldukları sütunlar değildir. Temel olarak, enum değerinin geçerli bir değer olduğunu doğrulayamazsınız, çünkü geçersiz bir değer ArgumentErrorherhangi bir doğrulamanın çalıştırılmasından önce bir değere neden olur . Bir stringtürün kullanılması doğrulama işlemine olanak sağlar, ancak performans maliyeti varsa, doğrulama sorununu çözmeyi tercih ederim.

Yanıtlar:


32

Kısa cevap: Her yönden integerdaha hızlı varcharveya daha hızlı text. Küçük masalar ve / veya kısa tuşlar için çok önemli değil. Fark, tuşların uzunluğu ve satır sayısı ile birlikte büyür.

string ... 20 karakter uzunluğunda, bellekte tamsayıdan kabaca 5 kat daha fazla (bir tamsayı 4 byte ise ve dizeler karakter başına 1 byte saf ASCII ise, o zaman bu tutar)

Kesin olarak, karakter türleri ( textveya varchar) diskte 20 ASCII karakter için tam olarak 21 bayt ve RAM'de 23 bayt tutar. Detaylı değerlendirme:

Ayrıca önemli: COLLATIONkurallar karakter verilerini sıralamayı daha pahalı hale getirebilir - sayısal veri türlerinin aksine:

Endeks büyüklüğü muhtemelen çoğu durumda performans farkının aslan payından sorumludur. Dizin demeti başına ek yükü göz önünde bulundurun (temelde tablodakiyle aynı): öğe işaretçisi için 4 bayt ve demet başlığı için 24 bayt . Yani için indeks tanımlama grubu integeranlamına geleceğini 36 byte (4 bayt dahil hizalama dolgusu ) ve için varchar(20)olurdu 20 ASCII karakterlerle 52 byte (aynı zamanda dahil. Dolgu). Detaylar:

Tüm teori bir yana: sadece test etmek en iyisi:

Postgres 9.5 , uzun karakter veri dizilerini (anahtar kelime "kısaltılmış tuşlar" ) ayırmak için bir optimizasyon sağlamıştır . Ancak Linux'ta bazı C kütüphanelerindeki bir hata, projeyi Postgres 9.5.2'deki C-dışı harmanlama özelliğini devre dışı bırakmaya zorladı. Sürüm notlarındaki detaylar.

Ancak, aslında Postgres enumtürlerini kullanıyorsanız, bu hususların çoğu ilgisizdir, çünkü bunlar integerzaten dahili olarak değerler ile uygulanır . Kullanım kılavuzu:

Bir enumdeğer diskte dört bayt kaplar.

Bir yana: varchar(255)SQL Server'ın ilk sürümleri için mantıklı olmak için kullanılır, bu dahili olarak 255 karakter sınırına kadar daha verimli bir veri türü kullanabilir. Ancak 255 karakterlik garip uzunluk kısıtlamasının Postgres'teki performans üzerinde hiçbir özel etkisi yoktur.


1
varchar(255)Örneğin , SQL Server'da örneğin hiçbir optimizasyon yoktur varchar(260). SQL Server 6.x ile böyle bir şey olabilirdi ama bu uzun süredir doğru değildi.
a_horse_with_no_name

@ a_horse_with_no_name: teşekkürler, buna göre açıklığa kavuşturdum.
Erwin Brandstetter

Bunu kabul etmek için çok zaman harcadığım için üzgünüm, o projenin geliştirilmesinde yavaş kaldım;)
Chris Cirefice

Bu cevap Postgres 10 için hala geçerli mi?
Matty

1
@Matty: Hala geçerli. Ayrıca pg 11 için de hiçbir şey değişmiyor.
Erwin Brandstetter
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.