Deze pagina is automatisch vertaald. Lees het Engelse origineel. English

IBSurgeon-bibliotheek

De verschillen tussen VARCHAR- en INTEGER-velden in sleutels

Ik gebruik integer-ID’s als primaire sleutels in mijn tabellen. Wat als ik in plaats daarvan varchar-velden zou gebruiken? Zal ik dan prestatie verliezen, vooral bij grote tabellen? Zullen joins nog steeds zo snel werken als bij de integer-kolom?

Je prestaties zouden ongeveer hetzelfde moeten zijn met varchars of integers. Firebird vergelijkt indexsleutels altijd bytegewijs en alleen het significante deel van de waarde wordt opgeslagen.

Een enkelvoudige veldsleutel wordt eerst geconverteerd naar een van de drie canonieke typen: string met collatie, double precision en (helaas) 64-bit integer. Datums worden double precision floating point getallen.

Strings met een andere collatie dan hun bytewaarde worden geconverteerd naar hun collatieformaat. Dat is enigszins een duistere kunst en vergroot de omvang van de string, maar het resultaat is dat de string zijn juiste plaats vindt wanneer deze wordt gesorteerd met andere strings van dezelfde collatie. ‘A’, ‘a’, ‘â’, ‘á’, ‘Ă’, ‘ã’, ‘ä’, ‘å’, ‘ă’, ‘ą’, ‘Ā’ verschijnen allemaal op hun toegewezen plaatsen. (Sorry voor wat dat met je e-mailclient heeft gedaan …. in de mijne zijn dat elf varianten van ‘A’.) Afsluitende spaties worden niet opgenomen in de sleutel.

Het double precision getal wordt gemanipuleerd zodat het ook bytegewijs sorteert - grofweg het teken omkeren, dan exponent, dan mantisse, met afkappen van afsluitende nullen.

Afhankelijk van de endianness van 64-bit integers op de computer, worden ook die gemanipuleerd zodat ze bytegewijs vergelijken. Dat lijkt misschien een optimalisatieverlies, maar indexsleutels worden niet op natuurlijke grenzen opgeslagen en ze ondergaan prefixcompressie, dus er is geen manier om een grotere vergelijking te gebruiken dan byte voor byte.

Samengestelde sleutels zijn grotendeels hetzelfde. Elk deel wordt geconverteerd naar zijn indexsleuteltype en opgevuld tot een veelvoud van 4 bytes. Na elke vier bytes voegt Firebird een byte toe met de positie van het huidige veld van de sleutel. Zo zou een index op Achternaam, Voornaam, Sterrenbeeld uitkomen als 1Harr1ison2Ann 3Gemi3ni. Dit voorkomt de verwarring tussen Damnation en Dam nation.

Waarom zei ik hierboven “(helaas)”? Omdat het hebben van één enkel formaat voor getallen Firebird in staat stelt om de grootte van getallen te wijzigen zonder indexen erop opnieuw te creëren. Maar toen Borland 64-bit integers terug toevoegde - InterBase had vanaf het begin 64-bit integers op Vaxes - realiseerde een slimme geest zich dat double precision 56 bits precisie heeft en 64-bit integers 64 bits. Aan de andere kant zijn Firebird-indexen ontworpen om enige onnauwkeurigheid te verwerken … of de resterende 8 bits konden aan het einde worden toegevoegd … wat dan ook. Dus je moet indexen herbouwen wanneer je van Numeric/Decimal 9 naar Numeric/Decimal 12 gaat. Helaas.

“Prefixcompressie?” Bij het opslaan van een sleutel die niet de eerste op een pagina is of de eerste na een sprong op de pagina, kijkt Firebird naar de voorgaande sleutel en truncateert dat deel van het begin van de volgende sleutel dat overeenkomt met zijn voorganger en plakt de lengte van het getrunceerde deel aan het begin. Zo worden de strings “AAAA”, “AAAB”, “AAAC”, “AABC”:

“AAAA”, “3B”, “3C” en “2BC”. Er is een probleem met sommige formaten van GUID’s die het variabele deel van het nummer eerst plaatsen, gevolgd door het vaste deel. Dat ondermijnt prefixcompressie en vergroot de omvang van indexen.

“Sprong?” - Prefixcompressie vermindert de omvang van indexen aanzienlijk, waardoor I/O afneemt, maar vereist het lezen over de hele pagina om de sleutel te ontcijferen. Prima met 1K-pagina’s, maar met grotere paginagroottes was de berekening onacceptabel. Dus elke indexpagina heeft nu een eigen index die verwijst naar de offsets van niet-gecomprimeerde items. Die index wordt een sprongvector genoemd.

Ann Harrision