Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Najszybszy sposób na obliczenie hash całej tabeli

Przede wszystkim myślę, że sposobem na podejście do „nieuczciwych administratorów” jest połączenie ścieżki audytu Oracle i Skarbiec bazy danych funkcje.

To powiedziawszy, oto co mogę spróbować:

1) Utwórz niestandardową funkcję agregującą ODCI, aby obliczyć skrót wielu wierszy jako agregację.2) Utwórz VIRTUAL NOT NULL kolumna w tabeli, która była hashem SHA wszystkich kolumn w tabeli — lub wszystkich tych, które chcesz chronić. Trzymałbyś to przez cały czas - w zasadzie wymień niektóre insert/update/delete w zamian za wydajność, aby móc szybciej obliczać skróty.3) Utwórz nieunikalny indeks na tej wirtualnej kolumnie4) SELECT my_aggregate_hash_function(virtual_hash_column) FROM my_table aby uzyskać wyniki.

Oto kod:

Utwórz funkcję agregującą, aby obliczyć skrót SHA dla kilku wierszy

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

Utwórz tabelę testową do pracy (pomiń to, ponieważ masz swój prawdziwy stół)

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

Utwórz skrót wirtualnej kolumny danych każdego wiersza. Upewnij się, że jest 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 ;

Utwórz indeks na wirtualnej kolumnie; w ten sposób możesz obliczyć swój skrót za pomocą pełnego skanu wąskiego indeksu zamiast pełnego skanu grubej tabeli

create index msi_compliance_hash_n1 on mattmsi (compliance_hash);  

Połącz to wszystko, aby obliczyć swój skrót

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

Kilka komentarzy:

  1. Myślę, że ważne jest, aby użyć skrótu do obliczenia agregacji (zamiast wykonywać tylko SUM() przez skróty na poziomie wiersza, ponieważ atakujący może bardzo łatwo sfałszować prawidłową sumę.
  2. Nie sądzę, że możesz (łatwo?) użyć zapytania równoległego ponieważ ważne jest, aby wiersze były przekazywane do funkcji agregującej w spójnej kolejności, w przeciwnym razie zmieni się wartość skrótu.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak umieścić więcej niż 1000 wartości w klauzuli Oracle IN

  2. Zmienna Oracle 11g Bind nie istnieje

  3. Dlaczego otrzymuję następującą funkcję LISTAGG błędu:„wynik konkatenacji ciągów jest za długi?*

  4. java.sql.SQLException:ORA-01005:podano puste hasło; Logowanie odrzucone

  5. Jak skonfigurować przydział rozmiaru w pliku persistence.xml zamiast Entity?