Hoe maak je een willekeurige string die geschikt is voor een sessie-ID in PostgreSQL?

Ik wil graag een willekeurige reeks maken voor gebruik bij sessieverificatie met PostgreSQL. Ik weet dat ik een willekeurig getal kan krijgen met SELECT random(), dus ik heb SELECT md5(random())geprobeerd, maar dat werkt niet. Hoe kan ik dit doen?


Antwoord 1, autoriteit 100%

U kunt uw eerste poging als volgt oplossen:

SELECT md5(random()::text);

Veel eenvoudiger dan sommige van de andere suggesties. 🙂


Antwoord 2, autoriteit 40%

Ik stel deze eenvoudige oplossing voor:

Dit is een vrij eenvoudige functie die een willekeurige string van de opgegeven lengte retourneert:

Create or replace function random_string(length integer) returns text as
$$
declare
  chars text[] := '{0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z}';
  result text := '';
  i integer := 0;
begin
  if length < 0 then
    raise exception 'Given length cannot be less than 0';
  end if;
  for i in 1..length loop
    result := result || chars[1+random()*(array_length(chars, 1)-1)];
  end loop;
  return result;
end;
$$ language plpgsql;

En het gebruik:

select random_string(15);

Voorbeelduitvoer:

select random_string(15) from generate_series(1,15);
  random_string
-----------------
 5emZKMYUB9C2vT6
 3i4JfnKraWduR0J
 R5xEfIZEllNynJR
 tMAxfql0iMWMIxM
 aPSYd7pDLcyibl2
 3fPDd54P5llb84Z
 VeywDb53oQfn9GZ
 BJGaXtfaIkN4NV8
 w1mvxzX33NTiBby
 knI1Opt4QDonHCJ
 P9KC5IBcLE0owBQ
 vvEEwc4qfV4VJLg
 ckpwwuG8YbMYQJi
 rFf6TchXTO3XsLs
 axdQvaLBitm6SDP
(15 rows)

Antwoord 3, autoriteit 12%

Voortbouwend op de oplossing van Marcin, kunt u dit doen door een willekeurig alfabet te gebruiken (in dit geval alle 62 ASCII-alfanumerieke tekens):

SELECT array_to_string(array 
       ( 
              select substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', trunc(random() * 62)::integer + 1, 1)
              FROM   generate_series(1, 12)), '');

Antwoord 4, autoriteit 12%

Je kunt 128 bits willekeurig krijgen van een UUID. Dit is de methode om de klus te klaren in moderne PostgreSQL.

CREATE EXTENSION pgcrypto;
SELECT gen_random_uuid();
           gen_random_uuid            
--------------------------------------
 202ed325-b8b1-477f-8494-02475973a28f

Misschien de documenten op UUID ook lezen

Het gegevenstype uuid slaat Universally Unique Identifiers (UUID) op zoals gedefinieerd door RFC 4122, ISO/IEC 9834-8:2005en gerelateerde standaarden. (Sommige systemen verwijzen in plaats daarvan naar dit gegevenstype als een globally unique identifier of GUID.) Deze identifier is een 128-bits hoeveelheiddie wordt gegenereerd door een algoritme dat is gekozen om het zeer onwaarschijnlijk te maken dat hetzelfde identifier wordt gegenereerd door iemand anders in het bekende universum met behulp van hetzelfde algoritme. Daarom bieden deze identifiers voor gedistribueerde systemen een betere uniciteitsgarantie dan sequentiegeneratoren, die alleen uniek zijn binnen een enkele database.

Hoe zeldzaam is een botsing met UUID, of te raden? Ervan uitgaande dat ze willekeurig zijn,

Er zouden ongeveer 100 biljoen versie 4 UUID’s moeten worden gegenereerd om een ​​kans van 1 op een miljard te hebben op een enkel duplicaat (“botsing”). De kans op één botsing stijgt pas tot 50% nadat er 261 UUID’s (2,3 x 10^18 of 2,3 quintillion) zijn gegenereerd. Als u deze getallen relateert aan databases, en rekening houdt met de vraag of de kans op een UUID-botsing van versie 4 verwaarloosbaar is, overweeg dan een bestand met 2,3 triljoen versie 4 UUID’s, met een kans van 50% op één UUID-botsing. Het zou 36 exabytes groot zijn, uitgaande van geen andere gegevens of overhead, duizenden keren groter dan de grootste databases die momenteel bestaan, die in de orde van petabytes zijn. Met een snelheid van 1 miljard UUID’s die per seconde worden gegenereerd, zou het 73 jaar duren om de UUID’s voor het bestand te genereren. Er zouden ook ongeveer 3,6 miljoen 10 terabyte harde schijven of tapecartridges nodig zijn om het op te slaan, ervan uitgaande dat er geen back-ups of redundantie zijn. Het lezen van het bestand met een typische “schijf-naar-buffer” overdrachtssnelheid van 1 gigabit per seconde zou meer dan 3000 jaar vergen voor een enkele processor. Aangezien het onherstelbare leesfoutpercentage van schijven op zijn best 1 bit per 1018 bits is, terwijl het bestand ongeveer 1020 bits zou bevatten, zou het slechts één keer lezen van het bestand van begin tot eind resulteren in op zijn minst ongeveer 100 keer meer fouten. lees UUID’s dan duplicaten. Opslag-, netwerk-, stroom- en andere hardware- en softwarefouten zouden ongetwijfeld duizenden keren vaker voorkomen dan UUID-duplicatieproblemen.

bron: wikipedia

Samengevat,

  • UUID is gestandaardiseerd.
  • gen_random_uuid()is 128 bits willekeurig opgeslagen in 128 bits (2**128 combinaties). 0-afval.
  • random()genereert slechts 52 bits willekeurig in PostgreSQL (2**52 combinaties) .
  • md5()opgeslagen als UUID is 128 bits, maar het kan alleen zo willekeurig zijn als de invoer (52 bits bij gebruik van random())
  • md5()opgeslagen als tekst is 288 bits, maar het kan alleen zo willekeurig zijn als de invoer (52 bits bij gebruik van random()) – meer dan tweemaal de grootte van een UUID en een fractie van de willekeur)
  • md5()als hash kan zo worden geoptimaliseerd dat het niet veel doet.
  • UUID is zeer efficiënt voor opslag: PostgreSQL biedt een type dat precies 128 bits is. In tegenstelling tot texten varchar, enz. die worden opgeslagen als een varlenadie overhead heeft voor de lengte van de string.
  • De handige UUID van PostgreSQL wordt geleverd met enkele standaardoperators, castings en functies.

Antwoord 5, autoriteit 6%

Ik speelde onlangs met PostgreSQL en ik denk dat ik een iets betere oplossing heb gevonden, door alleen ingebouwde PostgreSQL-methoden te gebruiken – geen pl/pgsql. De enige beperking is dat het momenteel alleen UPCASE-tekenreeksen genereert, of cijfers of tekenreeksen in kleine letters.

template1=> SELECT array_to_string(ARRAY(SELECT chr((65 + round(random() * 25)) :: integer) FROM generate_series(1,12)), '');
 array_to_string
-----------------
 TFBEGODDVTDM
template1=> SELECT array_to_string(ARRAY(SELECT chr((48 + round(random() * 9)) :: integer) FROM generate_series(1,12)), '');
 array_to_string
-----------------
 868778103681

Het tweede argument voor de methode generate_seriesbepaalt de lengte van de string.


Antwoord 6, autoriteit 6%

Gebruik a.u.b. string_agg!

SELECT string_agg (substr('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', ceil (random() * 62)::integer, 1), '')
FROM   generate_series(1, 45);

Ik gebruik dit met MD5 om ook een UUID te genereren. Ik wil gewoon een willekeurige waarde met meer bits dan een random ()geheel getal.


Antwoord 7, autoriteit 4%

Hoewel standaard niet actief, kunt u een van de kernextensies activeren:

CREATE EXTENSION IF NOT EXISTS pgcrypto;

Dan wordt je statement een simpele aanroep naar gen_salt() die een willekeurige string genereert:

select gen_salt('md5') from generate_series(1,4);
 gen_salt
-----------
$1$M.QRlF4U
$1$cv7bNJDM
$1$av34779p
$1$ZQkrCXHD

Het eerste nummer is een hash-ID. Er zijn verschillende algoritmen beschikbaar, elk met hun eigen identifier:

  • md5: $1$
  • bf: $2a$06$
  • des: geen identificatie
  • xdes: _J9..

Meer informatie over extensies:


BEWERKEN

Zoals aangegeven door Evan Carrol, kunt u vanaf v9.4 gen_random_uuid()

gebruiken

http://www.postgresql.org/docs/9.4/static /pgcrypto.html


Antwoord 8, autoriteit 3%

@Kavius ​​raadt aan om pgcryptote gebruiken , maar hoe zit het met gen_random_bytesin plaats van gen_random_bytes? En hoe zit het met sha512in plaats van md5?

create extension if not exists pgcrypto;
select digest(gen_random_bytes(1024), 'sha512');

Documenten:

F.25.5. Willekeurige gegevensfuncties

gen_random_bytes(count integer) geeft bytea terug

Retouren tellen cryptografisch sterke willekeurige bytes. Maximaal 1024
bytes kunnen tegelijk worden geëxtraheerd. Dit is om te voorkomen dat de
willekeurig generator pool.


Antwoord 9, autoriteit 2%

De parameter INTEGER definieert de lengte van de string. Dekt gegarandeerd alle 62 alfanumtekens met gelijke waarschijnlijkheid (in tegenstelling tot sommige andere oplossingen die rondzweven op internet).

CREATE OR REPLACE FUNCTION random_string(INTEGER)
RETURNS TEXT AS
$BODY$
SELECT array_to_string(
    ARRAY (
        SELECT substring(
            '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
            FROM (ceil(random()*62))::int FOR 1
        )
        FROM generate_series(1, $1)
    ), 
    ''
)
$BODY$
LANGUAGE sql VOLATILE;

Antwoord 10, autoriteit 2%

Ik denk niet dat je per se op zoek bent naar een willekeurige string. Wat u nodig heeft voor sessieverificatie, is een tekenreeks die gegarandeerd uniek is. Bewaart u informatie over sessieverificatie voor controle? In dat geval moet de string uniek zijn tussen sessies. Ik ken twee, vrij eenvoudige benaderingen:

  1. Gebruik een reeks. Goed voor gebruik op een enkele database.
  2. Gebruik een UUID. Universeel uniek, dus ook goed in gedistribueerde omgevingen.

UUID’s zijn gegarandeerduniek te zijn vanwege hun algoritme voor het genereren; in feite is het uiterstonwaarschijnlijk dat u twee identieke getallen op welke machine dan ook, op elk moment, ooit zult genereren (merk op dat dit veel sterker is dan op willekeurige reeksen, die een veel kleinere periodiciteit dan UUID’s).

U moet de uuid-ossp-extensie laden om UUID’s te gebruiken. Na de installatie roept u een van de beschikbare uuid_generate_vXXX()-functies aan in uw SELECT-, INSERT- of UPDATE-aanroepen. Het uuid-type is een getal van 16 bytes, maar het heeft ook een tekenreeksrepresentatie.


Antwoord 11, autoriteit 2%

select * from md5(to_char(random(), '0.9999999999999999'));

Other episodes