In Vorbereitung von Tests mit dem neuen Oracle DB 12c Spatial Feature "Vector Performance Accelerator" wollte ich mir ein ausreichend großes Datenset erzeugen.
Die Punktgeometrien zu generieren und in eine SDO_GEOMETRY-Tabelle zu laden, ist an sich keine schwere Übung. Die Frage ist hauptsächlich, wie lange man für das Schreiben der Daten in die Tabelle braucht.
Der herkömmliche Ansatz über ein PL/SQL-Skript (Skript 1) mit insert into <table> values ... in einer FOR Loop verlangt bei größeren Punktmengen - zumindest in meiner recht beschränkten virtuellen Testumgebung auf dem Laptop - doch einige Geduld.
set serveroutput on
drop table gps_positions purge;
create table gps_positions (
id number,
position sdo_geometry,
constraint gps_position_pk primary key (id) enable);
declare
l_curr_lon number;
l_curr_lat number;
i number;
j number;
id number;
l_start_time number;
l_end_time number;
begin
l_start_time := dbms_utility.get_time;
id := 1;
-- 100 x 1000 points
for i in 1 .. 100 loop
for j in 1 .. 1000 loop
l_curr_lat := round(dbms_random.value(-122,-74),10);
l_curr_lon := round(dbms_random.value(24,49),10);
insert into gps_positions (id, position) values (id, mdsys.sdo_geometry (2001, 4326, sdo_point_type (l_curr_lat, l_curr_lon, null), null, null));
id := id + 1;
-- dbms_output.put_line('GPS Point: ' ||id|| ' Lat: ' || l_curr_lat || ' Lon: ' || l_curr_lon);
commit;
end loop;
end loop;
commit;
l_end_time := dbms_utility.get_time;
dbms_output.put_line(to_char((l_end_time-l_start_time)/100));
end;
/
(Skript 1)
Ich bin aber gerade nicht geduldig, zumal wenn ich jetzt schon weiß, dass es durchaus mehr als 100K Punkte für die anstehenden Tests sein dürfen.
Also ist es an der Zeit, ein Bulk Insert mittels FORALL in meinem PL/SQL Skript auszuprobieren.
Und hier ist das veränderte Skript zum Erzeugen der Punkte in meiner GPS Tabelle.
set serveroutput on
drop table gps_positions purge;
create table gps_positions (
id number,
position sdo_geometry,
constraint gps_position_pk primary key (id) enable);
declare
type t_gps_positions is table of gps_positions%ROWTYPE;
l_tab t_gps_positions := t_gps_positions();
-- Sample size
l_size number := 100000;
l_start_time number;
l_end_time number;
l_lastid number;
l_curr_lon number;
l_curr_lat number;
l_geom sdo_geometry;
begin
-- Fetch last id from gps_positions table
select nvl(max(id),1) + 1 into l_lastid from gps_positions;
l_start_time := dbms_utility.get_time;
-- Populate sample as collection
for i in 1 .. l_size LOOP
l_curr_lat := round(dbms_random.value(-122,-74),10);
l_curr_lon := round(dbms_random.value(24,49),10);
l_geom := mdsys.sdo_geometry (2001, 4326, sdo_point_type (l_curr_lat, l_curr_lon, null), null, null);
l_tab.extend;
l_tab(l_tab.last).id := l_lastid;
l_tab(l_tab.last).position := l_geom;
l_lastid := l_lastid + 1;
end loop;
-- Ingest table with point geometries
forall i in l_tab.first .. l_tab.last
insert /*+ APPEND_VALUES */ into gps_positions values l_tab(i);
commit;
l_end_time := dbms_utility.get_time;
dbms_output.put_line(to_char((l_end_time-l_start_time)/100));
end;
/
(Skript 2)
Das Ganze dauert nur mehr gute 10 Sekunden, was 17x mal schneller war als beim 1. Ansatz.
Einen zusätzlichen Performanceschub zum reinen FORALL bringt hier übrigens noch der APPEND_VALUES Hint im insert.
Es versteht sich von selbst, dass anschließend noch die SDO-Metadaten registriert und der räumliche Index angelegt werden müssen.
Über die eigentlichen Tests mit dem Vector Performance Accelerator wird es dann in meinem nächsten Blogeintrag gehen.