Därefter skapar vi en tabell för personerna:CREATE TABLE Lander (ID INTEGER NOT NULL PRIMARY KEY, Namn NVARCHAR(50) NOT NULL UNIQUE);
Tabellen Lander har 205 rader, och tabellen Personer har 7 miljarder rader.CREATE TABLE Personer (ID BIGINT NOT NULL PRIMARY KEY, Personnummer BIGINT NOT NULL UNIQUE, -- unik, med index QU BIGINT NOT NULL, -- unik, utan index (obs: UNIQUE brukar skapa index) MI BIGINT NOT NULL, -- ej unik (men i genomsnitt en), med index MU BIGINT NOT NULL, -- ej unik (men i genomsnitt en), utan index Namn NVARCHAR(50) NOT NULL, Gatuadress NVARCHAR(30) NOT NULL, Stad NVARCHAR(20) NOT NULL, Land INTEGER NOT NULL REFERENCES Lander(ID), Telefon NVARCHAR(15) NOT NULL); CREATE INDEX ix_personer_MI on Personer(MI); CREATE INDEX ix_personer_telefon on Personer(Telefon);
Tabellen Lander har två index, på kolumnerna ID och Namn, och tabellen Personer har fyra index, på kolumnerna ID, Personnummer, MI och Telefon.
Här finns kommandon för att skapa och fylla dessa tabeller, men bara med de första tusen personerna: skapa-personer.txt
Vi antar att vi använder en normal, diskbaserad relationsdatabashanterare som använder sig av B+-trädsindex. Den har en bra frågeoptimerare. Data lagras på mekaniska hårddiskar (dvs inte SSD:er).
Redovisa resonemang och beräkningar.
a) Skriv en version av programmet som är känsligt för SQL Injection.
b) Skriv en version av programmet som inte är känsligt för SQL Injection.
Programmet ska använda sig av någon form av databasåtkomst inifrån programmet, till exempel med JDBC från ett Java-program, ODBC eller ESQL från ett C-program, ADO.NET, eller liknande.
a) Ange den systematiska översättningen av frågan, även kallad kanonisk form, till relationsalgebra. (Det är alltså den o-optimerade formen.) Skriv den som ett relationsalgebrauttryck.select Personer.ID, Personer.Namn from Personer, Lander where Personer.Land = Lander.ID and Personer.Telefon = '0744-123187' and Lander.Namn = 'Sverige';
b) Rita upp samma relationsalgebrauttryck som ett träd.
c) Visa hur en heuristisk frågeoptimerare, som inte tar hänsyn till datamängder eller lagringsstrukturer, optimerar den kanoniska formen. Visa både vilka olika optimeringar som görs, och vad slutresultatet blir.
d) Hur kommer den riktiga databashanteraren att optimera frågan, i den riktiga databasen med 7 miljarder personer? Hur skiljer sig den exekveringsplanen från den heuristiskt optimerade frågan ovan?
Här nedan finns också uppmätta tider från riktiga körningar mot databasen. Jämför sedan dina beräknade tider med de uppmätta tiderna, och försök förklara skillnaderna.
select * from Personer where ID = 2111614652; 1 row, 0.18 sec SELECT * FROM Personer WHERE ID IN (138288435, 527129368, 1607749915, 54568357, 7312927, 1785097992, 1750905710, 1801256587, 71280610, 1759394197); 6 rows, 1.40 sec select * from Personer where MI = 5685265372; 2 rows, 0.69 sec SELECT * FROM Personer WHERE MI IN (138288435, 527129368, 1607749915, 54568357, 7312927, 1785097992, 1750905710, 1801256587, 71280610, 1759394197); 9 rows, 1.63 sec select * from Personer where MU = 3298848664; 2 rows, 1 hour 56 min 57.02 sec SELECT * FROM Personer WHERE MU IN (138288435, 527129368, 1607749915, 54568357, 7312927, 1785097992, 1750905710, 1801256587, 71280610, 1759394197); 7 rows, 1 hour 57 min 27.52 sec
Därför har vi modifierat det givna i programmet incrementdb.c och skapat programmet badlog.c.
Den intressanta delen av badlog.c är skrivningarna till loggfilen i den här loopen:
Det finns ett eller flera fel med den här programkoden, som gör att loggningen av ändringarna inte kommer att fungera så bra, och inlämningsuppgiften blir förmodligen inte godkänd.position = 0; printf("Starting to update database file '%s'...\n", dbname); while (fread(&data, sizeof data, 1, db) == 1) { if (fseek(db, -(long)sizeof data, SEEK_CUR) != 0) { fprintf(stderr, "badlog: Couldn't fseek in database file '%s' (%s)\n", dbname, strerror(errno)); exit(EXIT_FAILURE); } data = data + 1; if (fwrite(&data, sizeof data, 1, db) != 1) { fprintf(stderr, "createdb: Couldn't write to database file '%s' (%s)\n", dbname, strerror(errno)); exit(EXIT_FAILURE); } if (fflush(db) != 0) { fprintf(stderr, "createdb: fflush failed on database file '%s' (%s)\n", dbname, strerror(errno)); exit(EXIT_FAILURE); } fprintf(log, "position: %d, change: +1\n", position); fprintf(log, "commit\n"); ++position; }
Vilka fel är det? Förklara också, för vart och ett av felen, varför det är fel.
Det kan vara lämpligt med en eller kanske två A4-sidor text för själva beskrivningen. Men ha gärna med förklarande exempel, och i så fall kan det gå åt ytterligare en eller flera sidor för exemplen.
Använd gärna källor, men: