sql >> Databasteknik >  >> RDS >> Oracle

Snabbaste sättet att beräkna hash för en hel tabell

Först och främst tror jag att sättet att närma sig "skurkiga administratörer" är med en kombination av Oracles revisionsspår och Databasvalv funktioner.

Som sagt, det här är vad jag kan testa:

1) Skapa en anpassad ODCI-aggregatfunktion för att beräkna en hash av flera rader som ett aggregat.2) Skapa en VIRTUAL NOT NULL kolumn i tabellen som var en SHA-hash för alla kolumner i tabellen – eller alla de du bryr dig om att skydda. Du skulle ha kvar det här hela tiden -- i princip byta bort lite insert/update/delete prestanda i utbyte för att kunna beräkna hash snabbare.3) Skapa ett icke-unikt index på den virtuella kolumnen4) SELECT my_aggregate_hash_function(virtual_hash_column) FROM my_table för att få resultaten.

Här är koden:

Skapa en aggregerad funktion för att beräkna en SHA-hash över ett gäng rader

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

Skapa en testtabell att arbeta med (du hoppar över detta eftersom du har din riktiga tabell)

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

Skapa en virtuell kolumnhash för varje rads data. Se till att det är 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 ;

Skapa ett index på den virtuella kolumnen; på så sätt kan du beräkna din hash med en fullständig genomsökning av det smala indexet istället för en fullständig genomsökning av fetttabellen

create index msi_compliance_hash_n1 on mattmsi (compliance_hash);  

Sätt ihop allt för att beräkna din hash

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

Några kommentarer:

  1. Jag tror att det är viktigt att använda en hash för att beräkna aggregatet (istället för att bara göra en SUM() över hasharna på radnivå, eftersom en angripare mycket lätt kan förfalska rätt summa.
  2. Jag tror inte att du (lätt?) kan använda parallell fråga eftersom det är viktigt att raderna matas till aggregatfunktionen i konsekvent ordning, annars ändras hashvärdet.


  1. ORA-01403 ingen data hittades fel

  2. Kodningsfel vid skrivning av data från excelfil till databas (mysql)

  3. JOIN Problem:Korrigera SQL-satsen som ska lösas:ORA-01799:en kolumn får inte vara yttre sammanfogad med en underfråga

  4. Påskynda radräkningen i MySQL