sql >> Database teknologi >  >> RDS >> Oracle

Hurtigste måde at beregne hash for en hel tabel

Først og fremmest tror jeg, at måden at henvende sig til "slyngelske administratorer" er med en kombination af Oracles revisionsspor og Database Vault funktioner.

Når det er sagt, her er hvad jeg kan prøve:

1) Opret en tilpasset ODCI-aggregatfunktion til at beregne en hash af flere rækker som en aggregat.2) Opret en VIRTUAL NOT NULL kolonne på bordet, der var en SHA-hash af alle kolonnerne i tabellen - eller alle dem, du interesserer dig for at beskytte. Du ville beholde dette hele tiden -- dybest set bytte nogle insert/update/delete væk ydeevne i bytte for at kunne beregne hash hurtigere.3) Opret et ikke-unik indeks på den virtuelle kolonne4) SELECT my_aggregate_hash_function(virtual_hash_column) FROM my_table for at få resultaterne.

Her er kode:

Opret en aggregeret funktion til at beregne en SHA-hash over en masse rækker

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;
/

Opret en testtabel at arbejde med (du springer dette over, da du har din rigtige tabel)

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

Opret en virtuel kolonnehash af hver rækkes data. Sørg for, at den er NOT NULL

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 ;

Opret et indeks på den virtuelle kolonne; på denne måde kan du beregne din hash med en fuld scanning af det smalle indeks i stedet for en fuld scanning af fedttabellen

create index msi_compliance_hash_n1 on mattmsi (compliance_hash);  

Sæt det hele sammen for at beregne din hash

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

Et par kommentarer:

  1. Jeg tror, ​​det er vigtigt at bruge en hash til at beregne aggregatet (i stedet for blot at lave en SUM() over hasherne på rækkeniveau, fordi en angriber meget nemt kunne forfalske den korrekte sum.
  2. Jeg tror ikke, du (let?) kan bruge parallel forespørgsel fordi det er vigtigt, at rækkerne føres til den samlede funktion i ensartet rækkefølge, ellers ændres hashværdien.


  1. Sådan administreres skrivebeskyttede DB-forbindelser på applikationsniveau

  2. hvordan tæller man rækker efter første bogstav?

  3. Indsæt manglende poster fra en tabel til en anden ved hjælp af mysql

  4. Kan ikke oprette JDBC-forbindelse til MySQL (ved hjælp af Java, IntelliJ og Linux)