15.2.2015

Tietokannat: Näkymät, indeksit ja herättimet


Näkymät / Views


CREATE VIEW Hinnasto
AS SELECT nimi, hinta FROM tuote

-- Käyttö

SELECT * FROM Hinnasto

Näkymän käyttö



CREATE VIEW ALVhinnasto(nimi, ALVhinta)
AS SELECT nimi, hinta*1.22
FROM TUOTE

Vinkkejä näkymien luontiin




Esimerkkejä näkymistä


CREATE VIEW turku AS
SELECT ptun, pnimi, priorit, sijainti
FROM projekti
WHERE sijainti = 'TURKU';


-- KÄYTTÖ:

SELECT *
FROM turku;

SELECT pnimi
FROM turku
WHERE pnimi like 'K%'
ORDER BY pnimi -- ORDER BY pitää olla täällä EI näkymän luonnissa!

CREATE VIEW hlot
(sukunimi, etunimi, htun, tutkinto, pvm, kunta, ostun) AS
SELECT snimi, enimi, htun, tutkinto, pvm, kunta, ostun
FROM henkilo


SELECT *
FROM hlot

Näkymän sarakeotsikoista

CREATE VIEW tunnit_yht AS
SELECT ptun, SUM(tunnit) AS yht
FROM proj_henk
GROUP BY ptun

SELECT *
FROM tunnit_yht

-- TAI

CREATE VIEW tunnit_yht (ptun, yht) AS -- sarakeotsikot oltava täällä, jos funktioita ilman aliaksia
SELECT ptun, SUM(tunnit)
FROM proj_henk
GROUP BY ptun

SELECT *
FROM tunnit_yht

Indeksit



CREATE INDEX i_postinro ON henkilo(postinro)

CREATE UNIQUE INDEX i_sarake ON taulu(sarake)

Indeksien käyttö




Peukalosääntö indeksin luomiselle (nk. 3 tähden indeksi)

  1. Ota kaikki WHERE-kohdassa mainitut sarakkeet
  2. Lisää ORDER BY –kohdassa mainitut sarakkeet
  3. Laita loppuun SELECT-lauseessa olevat sarakenimet

Esimerkiksi kyselylle
SELECT eka, toka, koka FROM taulu WHERE neka = ’x’ ORDER BY toka
paras mahdollinen indeksi olisi
CREATE INDEX i_nekatokaekakoka ON taulu(neka,toka,eka,koka)



Indeksit: miten?, vaikutus suorituskykyyn


Luodaan testitaulu


-- Luodaan taulu, lisätään dataa, katsotaan tulos

CREATE TABLE henkilot (
tunnus varchar(6) not null,
sukunimi varchar(128) not null,
etunimi varchar(128) not null,
osoite varchar(255) not null,
puhnro varchar(64) not null,
email varchar(128),
PRIMARY KEY (tunnus),
UNIQUE (email)
);

INSERT INTO henkilot VALUES
('havpen', 'Haverinen', 'Pentti', 'Poritie 4', '00001','pena@server.fi'),
('kanvis','Kanninen','Visa','Kumpiuja 2','11234','kane@abcde.fi'),
('polrau','Polkunen','Rauno','Umpikuja 1','01234','rane@abcde.fi');

SELECT * FROM henkilo;

Tutkitaan indeksejä

-- Katsotaan indeksi

SHOW INDEX FROM henkilot;
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| henkilot | 0 | PRIMARY | 1 | tunnus | A | 3 | NULL | NULL | | BTREE | |
| henkilot | 0 | email | 1 | email | A | 3 | NULL | NULL | YES | BTREE | |
+----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

-- --> Indeksit PRIMARY ja email.
-- --> Cardinality ~ indeksin yksittäisten arvojen lkm ~ rivien lkm

-- Kaikki indeksit:

SELECT DISTINCT TABLE_NAME, INDEX_NAME
FROM INFORMATION_SCHEMA.STATISTICS;

-- henkilot-taulujen indeksit:

SELECT DISTINCT TABLE_NAME, INDEX_NAME
FROM INFORMATION_SCHEMA.STATISTICS
WHERE TABLE_NAME = 'henkilot';

Luodaan 200 000 tietuetta PHP-ohjelmalla

-- Luodaan PHP-ohjelma teeiso.php esim.
-- nano teeiso.php

<?php
$fp = fopen("file.sql", "a+");
for($i=1;$i<=200000;$i++) {
fwrite($fp,"INSERT INTO henkilot VALUES('$i','Suku$i','E$i','O$i','$i','$i@com');\n");
}
fclose($fp);
?>

-- Ajetaan PHP-ohjelma:

php teeiso.php

-- tuloksena tiedosto file.sql, jonka ekat ja vimpat rivit:

head -3 file.sql
INSERT INTO henkilot VALUES('1','Suku1','E1','O1','1','1@com');
INSERT INTO henkilot VALUES('2','Suku2','E2','O2','2','2@com');
INSERT INTO henkilot VALUES('3','Suku3','E3','O3','3','3@com');
tail -3 file.sql
INSERT INTO henkilot VALUES('199998','Suku199998','E199998','O199998','199998','199998@com');
INSERT INTO henkilot VALUES('199999','Suku199999','E199999','O199999','199999','199999@com');
INSERT INTO henkilot VALUES('200000','Suku200000','E200000','O200000','200000','200000@com');


-- Syötetään rivit ara-nimiseen tietokantaan,
-- kestänee muutaman minuutin, mutta ei 10 min kauempaa:

mysql -u ara -pSALASANA -h mysql.labranet.jamk.fi ara < file.sql

Testataan

mysql -u ara -pSALASANA -h mysql.labranet.jamk.fi ara

mysql> SELECT COUNT(*) FROM henkilot;
+----------+
| COUNT(*) |
+----------+
| 200003 |
+----------+
1 row in set (0.04 sec)


mysql> SELECT sukunimi FROM henkilot WHERE tunnus = 175175;
+------------+
| sukunimi |
+------------+
| Suku175175 |
+------------+
1 row in set (0.21 sec)


mysql> SELECT sukunimi FROM henkilot WHERE tunnus = 175175;
+------------+
| sukunimi |
+------------+
| Suku175175 |
+------------+
1 row in set (0.00 sec)


mysql> SELECT sukunimi FROM henkilot WHERE sukunimi = 'suku175175';
+------------+
| sukunimi |
+------------+
| Suku175175 |
+------------+
1 row in set (0.10 sec)


mysql> CREATE INDEX i_sukunimi ON henkilot(sukunimi);
Query OK, 200003 rows affected (2.82 sec)
Records: 200003 Duplicates: 0 Warnings: 0

mysql> SHOW INDEX FROM henkilot;
+----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| henkilot | 0 | PRIMARY | 1 | tunnus | A | 199249 | NULL | NULL | | BTREE | |
| henkilot | 0 | email | 1 | email | A | 199249 | NULL | NULL | YES | BTREE | |
| henkilot | 1 | i_sukunimi | 1 | sukunimi | A | 199249 | NULL | NULL | | BTREE | |
+----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
3 rows in set (0.00 sec)


mysql> SELECT sukunimi FROM henkilot WHERE sukunimi = 'suku176111';
+------------+
| sukunimi |
+------------+
| Suku176111 |
+------------+
1 row in set (0.01 sec)


mysql> SELECT sukunimi FROM henkilot WHERE etunimi = 'e175175';
+------------+
| sukunimi |
+------------+
| Suku175175 |
+------------+
1 row in set (0.09 sec)




Herättimet (triggers)




Check-rajoitteen toteuttaminen herättimellä (MySQL)



-- Luodaan taulu ja lisätään dataa
CREATE TABLE taulu (luku INT) TYPE=InnoDB;
INSERT INTO taulu(luku) VALUES (1);
INSERT INTO taulu(luku) VALUES (2);
INSERT INTO taulu(luku) VALUES (3);


mysql> show triggers;
Empty set (0.00 sec)


-- Herätin lisäyksiä varten
DELIMITER $$

CREATE TRIGGER trigger1
BEFORE INSERT ON taulu
FOR EACH ROW
BEGIN
IF !(NEW.luku >=0) THEN
CALL `Virhe: Virheellinen arvo sarakkeeseen luku Uusi tietue`;
END IF;
END$$

DELIMITER ;

-- Herätin lisäyksiä varten
DELIMITER $$

CREATE TRIGGER trigger2
BEFORE UPDATE ON taulu
FOR EACH ROW
BEGIN
IF !(NEW.luku >=0) THEN
CALL `Virhe: Virheellinen arvo sarakkeeseen luku! Uusi tietue`;
END IF;
END$$

DELIMITER ;

--
mysql> show triggers;

+----------+----------+----------+----------+
| Trigger |
+----------+----------+----------+----------+
| trigger1 |
...

-- Lisätään dataa:

mysql> INSERT INTO taulu VALUES (4);
Query OK, 1 row affected (0.01 sec)

-- Yritetään lisätä
mysql> INSERT INTO taulu VALUES (-4);
ERROR 1305 (42000): PROCEDURE ara.Virhe: Virheellinen arvo sarakkeeseen luku Uusi tietue does not exist

-- Yritetään päivittää
mysql> UPDATE taulu set luku = -4 WHERE luku = 4;
ERROR 1305 (42000): PROCEDURE ara.Virhe: Virheellinen arvo sarakkeeseen luku Uusi tietue does not exist

-- Herättimien poistaminen haluttaessa:

mysql> drop trigger trigger1;
mysql> drop trigger trigger2;



Osa materiaalista on muokattu Jouni Huotarin materiaalista.