sql >> Database >  >> RDS >> Oracle

Snelste manier om hash van een hele tabel te berekenen

Allereerst denk ik dat de manier om "schurkenstaten" te benaderen is met een combinatie van Oracle's audit trail en Databasekluis functies.

Dat gezegd hebbende, dit is wat ik zou kunnen proberen:

1) Maak een aangepaste ODCI-aggregatiefunctie om een ​​hash van meerdere rijen als een aggregaat te berekenen.2) Maak een VIRTUAL NOT NULL kolom op de tabel die een SHA-hash was van alle kolommen in de tabel - of alle kolommen die u wilt beschermen. Je zou dit de hele tijd bewaren -- in feite verhandelen sommige insert/update/delete prestatie in ruil om hashes sneller te kunnen berekenen.3) Maak een niet-unieke index op die virtuele kolom4) SELECT my_aggregate_hash_function(virtual_hash_column) FROM my_table om de resultaten te krijgen.

Hier is de code:

Maak een aggregatiefunctie om een ​​SHA-hash te berekenen over een aantal rijen

CREATE OR REPLACE TYPE matt_hash_aggregate_impl AS OBJECT
(
  hash_value RAW(32000),
  CONSTRUCTOR FUNCTION matt_hash_aggregate_impl(SELF IN OUT NOCOPY matt_hash_aggregate_impl ) RETURN SELF AS RESULT,  
-- Called to initialize a new aggregation context
-- For analytic functions, the aggregation context of the *previous* window is passed in, so we only need to adjust as needed instead 
-- of creating the new aggregation context from scratch
  STATIC FUNCTION ODCIAggregateInitialize (sctx IN OUT matt_hash_aggregate_impl) RETURN NUMBER,
-- Called when a new data point is added to an aggregation context  
  MEMBER FUNCTION ODCIAggregateIterate (self IN OUT matt_hash_aggregate_impl, value IN raw ) RETURN NUMBER,
-- Called to return the computed aggragate from an aggregation context
  MEMBER FUNCTION ODCIAggregateTerminate (self IN matt_hash_aggregate_impl, returnValue OUT raw, flags IN NUMBER) RETURN NUMBER,
-- Called to merge to two aggregation contexts into one (e.g., merging results of parallel slaves) 
  MEMBER FUNCTION ODCIAggregateMerge (self IN OUT matt_hash_aggregate_impl, ctx2 IN matt_hash_aggregate_impl) RETURN NUMBER,
  -- ODCIAggregateDelete
  MEMBER FUNCTION ODCIAggregateDelete(self IN OUT matt_hash_aggregate_impl, value raw) RETURN NUMBER  
);

/

CREATE OR REPLACE TYPE BODY matt_hash_aggregate_impl IS

CONSTRUCTOR FUNCTION matt_hash_aggregate_impl(SELF IN OUT NOCOPY matt_hash_aggregate_impl ) RETURN SELF AS RESULT IS
BEGIN
  SELF.hash_value := null;
  RETURN;
END;


STATIC FUNCTION ODCIAggregateInitialize (sctx IN OUT matt_hash_aggregate_impl) RETURN NUMBER IS
BEGIN
  sctx := matt_hash_aggregate_impl ();
  RETURN ODCIConst.Success;
END;


MEMBER FUNCTION ODCIAggregateIterate (self IN OUT matt_hash_aggregate_impl, value IN raw ) RETURN NUMBER IS
BEGIN
  IF self.hash_value IS NULL THEN
    self.hash_value := dbms_crypto.hash(value, dbms_crypto.hash_sh1);
  ELSE 
      self.hash_value := dbms_crypto.hash(self.hash_value || value, dbms_crypto.hash_sh1);
  END IF;
  RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateTerminate (self IN matt_hash_aggregate_impl, returnValue OUT raw, flags IN NUMBER) RETURN NUMBER IS
BEGIN
  returnValue := dbms_crypto.hash(self.hash_value,dbms_crypto.hash_sh1);
  RETURN ODCIConst.Success;
END;

MEMBER FUNCTION ODCIAggregateMerge (self IN OUT matt_hash_aggregate_impl, ctx2 IN matt_hash_aggregate_impl) RETURN NUMBER IS
BEGIN
    self.hash_value := dbms_crypto.hash(self.hash_value || ctx2.hash_value, dbms_crypto.hash_sh1);
  RETURN ODCIConst.Success;
END;

-- ODCIAggregateDelete
MEMBER FUNCTION ODCIAggregateDelete(self IN OUT matt_hash_aggregate_impl, value raw) RETURN NUMBER IS
BEGIN
  raise_application_error(-20001, 'Invalid operation -- hash aggregate function does not support windowing!');
END;  

END;
/

CREATE OR REPLACE FUNCTION matt_hash_aggregate ( input raw) RETURN raw
PARALLEL_ENABLE AGGREGATE USING matt_hash_aggregate_impl;
/

Maak een testtabel om mee te werken (je slaat dit over omdat je je echte tafel hebt)

create table mattmsi as select * from mtl_system_items where rownum <= 200000;

Maak een virtuele kolomhash van de gegevens van elke rij. Zorg ervoor dat het NOT NULL is

alter table mattmsi add compliance_hash generated always as ( dbms_crypto.hash(to_clob(inventory_item_id || segment1 || last_update_date || created_by || description), 3 /*dbms_crypto.hash_sh1*/) ) VIRTUAL not null ;

Maak een index op de virtuele kolom; op deze manier kunt u uw hash berekenen met een volledige scan van de smalle index in plaats van een volledige scan van de vettabel

create index msi_compliance_hash_n1 on mattmsi (compliance_hash);  

Zet alles bij elkaar om je hash te berekenen

SELECT matt_hash_aggregate(compliance_hash) from (select compliance_hash from mattmsi order by compliance_hash);

Een paar opmerkingen:

  1. Ik denk dat het belangrijk is om een ​​hash te gebruiken om het totaal te berekenen (in plaats van alleen een SUM() te doen over de hashes op rijniveau, omdat een aanvaller heel gemakkelijk de juiste som kan vervalsen.
  2. Ik denk niet dat je (gemakkelijk?) parallelle zoekopdracht kunt gebruiken omdat het belangrijk is dat de rijen in consistente volgorde aan de aggregatiefunctie worden ingevoerd, anders verandert de hash-waarde.


  1. MySQL:selecteer gegevens uit een tabel waarvan de datum in de huidige week en de huidige maand valt

  2. Haal de dichtstbijzijnde datum uit de MySQL-tabel

  3. Wat zijn de gegevens en informatie en gegevensvolumes?

  4. PostgreSQL-trends:populairste cloudproviders, talen, VACUUM, strategieën voor querybeheer en implementatietypen in ondernemingen