sql >> Databáze >  >> RDS >> Oracle

Nejrychlejší způsob, jak vypočítat hash celé tabulky

Za prvé, myslím, že způsob, jak oslovit „nečestné administrátory“, je kombinace audit trail společnosti Oracle a Databázový trezor funkce.

To znamená, že bych to mohl zkusit:

1) Vytvořte vlastní agregační funkci ODCI pro výpočet hash více řádků jako agregaci.2) Vytvořte VIRTUAL NOT NULL sloupec v tabulce, který byl SHA hash všech sloupců v tabulce – nebo všech sloupců, na kterých vám záleží na ochraně. Tohle byste si nechali pořád – v podstatě vyměnili nějaké insert/update/delete výkon výměnou, abyste mohli rychleji vypočítat hash.3) Vytvořte nejedinečný index na tomto virtuálním sloupci4) SELECT my_aggregate_hash_function(virtual_hash_column) FROM my_table získat výsledky.

Zde je kód:

Vytvořte agregační funkci pro výpočet hodnoty hash SHA nad hromadou řádků

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

Vytvořte si testovací tabulku, se kterou budete pracovat (tento krok přeskočte, protože máte svůj skutečný stůl)

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

Vytvořte virtuální sloupec hash dat každého řádku. Ujistěte se, že je 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 ;

Vytvořte index na virtuálním sloupci; tímto způsobem můžete vypočítat svůj hash pomocí úplného skenování úzkého indexu namísto úplného skenování tlusté tabulky

create index msi_compliance_hash_n1 on mattmsi (compliance_hash);  

Dejte vše dohromady, abyste vypočítali hash

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

Pár komentářů:

  1. Domnívám se, že k výpočtu agregace je důležité použít hash (místo pouhého provedení SUM() přes hash na úrovni řádku, protože útočník by mohl velmi snadno zfalšovat správný součet.
  2. Nemyslím si, že můžete (snadno?) použít paralelní dotaz protože je důležité, aby byly řádky přiváděny do agregační funkce v konzistentním pořadí, jinak se hodnota hash změní.


  1. zahrnout třídu Jfactory do externího souboru php, Joomla

  2. Jak používat nativní heslo s MySQL 5.7

  3. Jak zjistit, zda upsert byl aktualizací s PostgreSQL 9.5+ UPSERT?

  4. jak vytvořit spouštěč pro zřetězení polí