¡Esta es una revisión vieja del documento!
/* … */
CREATE DATABASE nombre
CREATE DATABASE bookstore;
CREATE TABLE nombre (columna tipo propiedades, columna tipo propiedades…)
CREATE TABLE books ( rec_id INT, title VARCHAR(50), author VARCHAR(50) );
ALTER TABLE nombre modificiación, modificación…
Las modificaciones posibles:
ADD COLUMN columna tipo propiedadesCHANGE COLUMN columna nuevo_nombre tipo propiedadesALTER TABLE books CHANGE COLUMN rec_id rec_id INT AUTO_INCREMENT PRIMARY KEY, CHANGE COLUMN author author_id INT, ADD COLUMN description BLOB;
Las enumeraciones se asignan entre parentesis un grupo de valores que aceptan, estos entre comillas simples:
ENUM ('yes', 'no')ENUM('novel','poetry','drama')
Si se le asigna un valor que no existe provoca un warning e inserta un valor en blanco. Cada valor insertado recibe un número, siendo el primero 1, el segundo 2… Y el valor en blanco un 0. Por lo que puedes hacer selects preguntando por el valor numérico o el valor dado.
Los ENUM ocupan: 1 byte si tienen menos de 255 elementos o 2 bytes si tienen menos 65535. Los SET, en cambio, ocupan mucho más (1-8 elementos: 1byte, 9-16 elementos: 2 bytes… 33-64 elementos: 8 bytes).
La sintaxis para definir una foreign key en MySql es:
[CONSTRAINT símbolo] FOREIGN KEY (nombre_columna, ...) REFERENCES nombre_tabla (nombre_columna, ...) [ON DELETE {CASCADE | SET NULL | NO ACTION | RESTRICT}] [ON UPDATE {CASCADE | SET NULL | NO ACTION | RESTRICT}]
CREATE TABLE publicaciones (isbn VARCHAR(10) PRIMARY KEY, id_editorial INT, FOREIGN KEY (id_editorial) REFERENCES editoriales(id));
Un ejemplo para añadir una foreign key tras haber creado la tabla:
ALTER TABLE venta ADD FOREIGN KEY(id_cliente) REFERENCES cliente(id_cliente);
DROP TABLE nombre
DROP TABLE books;
Opcionalmente puedes añadir IF EXISTS tras TABLE, de esa forma si la tabla no existe el comando no dará error:
DROP TABLE IF EXISTS books;
CREATE TABLE rel_autores_publicaciones (id_autor INT, isbn VARCHAR(10), PRIMARY KEY (id_autor, isbn), FOREIGN KEY (id_autor) REFERENCES autores(id), FOREIGN KEY (isbn) REFERENCES publicaciones(isbn)); CREATE TABLE diccionarios (isbn VARCHAR(10) PRIMARY KEY, id_idioma1 INT NOT NULL, id_idioma2 INT, FOREIGN KEY (isbn) REFERENCES publicaciones(idiomas), FOREIGN KEY (id_idioma1) REFERENCES idiomas (id), FOREIGN KEY (id_idioma2) REFERENCES idiomas(id));
INSERT INTO tabla (campo1, campo2…) VALUES (valorNumerico, 'valorString'…)
INSERT INTO authors (author_last, author_first, country) VALUES('Vernon','Olympia','USA');
UPDATE tabla SET campo1=valor1, campo2=valor2, … [WHERE columnaN=valorN]
UPDATE City SET Population=5000000 WHERE Name='JoanBrossa'; UPDATE City SET Population=5000000 WHERE Population<1000000;
SELECT campos FROM tablas [WHERE condicion] [ORDER BY campoOrden tipoOrden] [LIMIT límite]
tabla.campo si queremos hacer un select de campos de distintas tablas.* si queremos decir todos.campo AS nombre.tabla AS otro_nombre, luego en los campos tenemos que usar otro_nombre.campo.[En: MySQL] Expresiones Regulares: REGEXP, RLIKE o NOT REGEXP.LIMIT 3, 2, mostraría el 4º y el 5º registro.SELECT * FROM books; SELECT title, description FROM books; SELECT title AS titulo FROM books; SELECT rec_id, title, description FROM books WHERE genre = 'novel'; SELECT * FROM books ORDER BY title, pub_year LIMIT 20, 10; SELECT books.title, a.name FROM books, authors AS a; SELECT * FROM autores WHERE nombre REGEXP 'r{2}';
Imaginemos una BD donde tenemos una relación de películas\director, para sacar películas por director haremos:
SELECT title, name FROM movies m, directors d WHERE m.director = d.id;
Con JOIN sería:
SELECT title, name FROM movies m INNER JOIN directors d ON (m.director = d.id);
Los joins funcionan de la siguiente manera:
En el siguiente ejemplo se buscan todos los contactos que puede ver el trabajador 1 (los suyos y los que son públicos (visibilidad = 1)):
SELECT * FROM Contactos WHERE Contactos.id IN (SELECT Contactos.id FROM Contactos, RelContTrab WHERE RelConTrab.idCon = Contactos.id AND RelConTrab.idTrab = 1) OR Contactos.id IN (SELECT Contactos.id FROM Contactos WHERE Contactos.Visibility = 1);
También podemos pedir campos que estén o no en una lista:
SELECT * FROM tags WHERE id NOT IN (SELECT id FROM Elements); SELECT * FROM tags WHERE id IN (3, 4, 5);
SELECT COUNT(*) FROM users;
SELECT ciudad.nombre, SUM(pueblo.hab) FROM pueblo, ciudad WHERE (pueblo.id_ciudad = ciudad.id) GROUP BY (ciudad.nombre);
Teniendo dos tablas:
CREATE TABLE b (ca INT, cb INT); CREATE TABLE c (xa INT, xb INT);
Insertamos en la tabla b unos datos cb con un identificador ca (que puede estar repetido), ahora queremos insertar en la tabla c la suma de los valores cb con un mismo identificador:
INSERT INTO c (xa, xb) SELECT ca, SUM(cb) FROM b GROUP BY ca;
1. Not using appropriate indexes
This is a relatively easy one but still it happens all the time. Foreign keys should have indexes on them. If you're using a field in a WHERE you should (probably) have an index on it. Such indexes should often cover multiple columns based on the queries you need to execute.
2. Not enforcing referential integrity
Your database may vary here but if your database supports referential integrity–meaning that all foreign keys are guaranteed to point to an entity that exists–you should be using it.
It's quite common to see this failure on MySQL databases. I don't believe MyISAM supports it. InnoDB does. You'll find people who are using MyISAM or those that are using InnoDB but aren't using it anyway.
More here:
3. Using natural rather than surrogate (technical) primary keys
Natural keys are keys based on externally meaningful data that is (ostensibly) unique. Common examples are product codes, two-letter state codes (US), social security numbers and so on. Surrogate or technical primary keys are those that have absolutely no meaning outside the system. They are invented purely for identifying the entity and are typically auto-incrementing fields (SQL Server, MySQL, others) or sequences (most notably Oracle).
In my opinion you should always use surrogate keys. This issue has come up in these questions:
This is a somewhat controversial topic on which you won't get universal agreement. While you may find some people who think natural keys are, in some situations OK, you won't find any criticism of surrogate keys other than being arguably unnecessary. That's quite a small downside if you ask me.
Remember, even countries can cease to exist (eg Yugoslavia).
4. Writing queries that require DISTINCT to work
You often see this in ORM-generated queries. Look at the log output from Hibernate and you'll see all the queries begin with:
SELECT DISTINCT …
This is a bit of a shortcut to ensuring you don't return duplicate rows and thus get duplicate objects. You'll sometimes see people doing this as well. If you see it too much it's a real red flag. Not that DISTINCT is bad or doesn't have valid applications. It does (on both counts) but it's not a surrogate or a stopgap for writing correct queries.
From Why I Hate DISTINCT:
Where things start to go sour in my opinion is when a developer is building substantial query, joining tables together, and all of a sudden he realizes that it looks like he is getting duplicate (or even more) rows and his immediate response...his "solution" to this "problem" is to throw on the DISTINCT keyword and POOF all his troubles go away.
5. Favouring aggregation over joins
Another common mistake by database application developers is to not realize how much more expensive aggregation (ie the GROUP BY clause) can be compared to joins.
To give you an idea of how widespread this is, I've written on this topic several times here and been downvoted a lot for it. For example:
From SQL Statement - “Join” Vs “Group By and Having”:
First query:
SELECT userid FROM userrole WHERE roleid IN (1, 2, 3) GROUP by userid HAVING COUNT(1) = 3
Query time: 0.312s
Second query:
SELECT t1.userid FROM userrole t1 JOIN userrole t2 ON t1.userid = t2.userid AND t2.roleid = 2 JOIN userrole t3 ON t2.userid = t3.userid AND t3.roleid = 3 AND t1.roleid = 1
Query time: 0.016s
That's right. The join version I proposed is twenty times faster than the aggregate version.
6. Not simplifying complex queries through views
Not all database vendors support views but for those that do, they can greatly simplify queries if used judiciously. For example, on one project I used a generic Party model for CRM. This is an extremely powerful and flexible modelling technique but can lead to many joins. In this model there were:
Example:
So there are five tables joined to link Ted to his employer. You assume all employees are Persons (not organisations) and provide this helper view:
CREATE VIEW vw_employee AS SELECT p.title, p.given_names, p.surname, p.date_of_birth, p2.party_name employer_name FROM person p JOIN party py ON py.id = p.id JOIN party_role child ON p.id = child.party_id JOIN party_role_relationship prr ON child.id = prr.child_id AND prr.type = 'EMPLOYMENT' JOIN party_role parent ON parent.id = prr.parent_id = parent.id JOIN party p2 ON parent.party_id = p2.id
And suddenly you have a very simple view of the data you want but on a highly flexible data model.
7. Not sanitizing input
This is a huge one. Now I like PHP but if you don't know what you're doing it's really easy to create sites vulnerable to attack. Nothing sums it up better than the story of little Bobby Tables.
Data provided by the user by way of URLs, form data and cookies should always be treated as hostile and sanitized. Make sure you're getting what you expect.
8. Not using prepared statements
Prepared statements are when you compile a query minus the data used in inserts, updates and WHERE clauses and then supply that later. For example:
SELECT * FROM users WHERE username = 'bob'
vs
SELECT * FROM users WHERE username = ?
or
SELECT * FROM users WHERE username = :username
depending on your platform.
I've seen databases brought to their knees by doing this. Basically, each time any modern database encounters a new query it has to compile it. If it encounters a query it's seen before, you're giving the database the opportunity to cache the compiled query and the execution plan. By doing the query a lot you're giving the database the opportunity to figure that out and optimize accordingly (eg by pinning the compiled query in memory).
Using prepared statements will also give you meaningful statistics about how often certain queries are used.
Prepared statements will also better protect you against SQL injection attacks.
9. Not normalizing enough
Database normalization is basically the process of optimizing database design or how you organize your data into tables.
Just this week I ran across some code where someone had imploded an array and inserted it into a single field in a database. Normalizing that would be to treat element of that array as a separate row in a child table (ie a one-to-many relationship).
This also came up in Best Method for Storing a List of User IDs:
I've seen in other systems that the list is stored in a serialized PHP array.
But lack of normalization comes in many forms.
More:
10. Normalizing too much
This may seem like a contradiction to the previous point but normalization, like many things, is a tool. It is a means to an end and not an end in and of itself. I think many developers forget this and start treating a “means” as an “end”. Unit testing is a prime example of this.
I once worked on a system that had a huge hierarchy for clients that went something like:
Licensee → Dealer Group → Company → Practice → …
such that you had to join about 11 tables together before you could get any meaningful data. It was a good example of normalization taken too far.
More to the point, careful and considered denormalization can have huge performance benefits but you have to be really careful when doing this.
More:
11. Using exclusive arcs
An exclusive arc is a common mistake where a table is created with two or more foreign keys where one and only one of them can be non-null. Big mistake. For one thing it becomes that much harder to maintain data integrity. After all, even with referential integrity, nothing is preventing two or more of these foreign keys from being set (complex check constraints notwithstanding).
From A Practical Guide to Relational Database Design:
We have strongly advised against exclusive arc construction wherever possible, for the good reason that they can be awkward to write code and pose more maintenance difficulties.
11. Not doing performance analysis on queries at all
Pragmatism reigns supreme, particularly in the database world. if you're sticking to principles to the point that they've become a dogma then you've quite probably made mistakes. Take the example of the aggregate queries from above. The aggregate version might look “nice” but it's performance is woeful. A performance comparison should've ended the debate (but it didn't) but more to the point: spouting such ill-informed views in the first place is ignorant, even dangerous.
12. Over-reliance on UNION ALL and particularly UNION constructs
A UNION in SQL terms merely concatenates congruent data sets, meaning they have the same type and number of columns. The difference between them is that UNION ALL is a simple concatenation and should be preferred wherever possible whereas a UNION will implicitly do a DISTINCT to remove duplicate tuples.
UNIONs, like DISTINCT, have their place. There are valid applications. But if you find yourself doing a lot of them, particularly in subqueries, then you're probably doing something wrong. That might be a case of poor query construction or a poorly designed data model forcing you to do such things.
UNIONs, particularly when used in joins or dependent subqueries, can cripple a database. Try to avoid them whenever possible.
13. Using OR conditions in queries
This might seem harmless. After all, ANDs are OK. OR should be OK too right? Wrong. Basically an AND condition restricts the data set whereas an OR condition grows it but not in a way that lends itself to optimisation. Particularly when the different OR conditions might intersect thus forcing the optimizer to effectively to a DISTINCT operation on the result.
Bad:
… WHERE a = 2 OR a = 5 OR a = 11
Better:
… WHERE a IN (2, 5, 11)
Now your SQL optimizer may effectively turn the first query into the second. But it might not. Just don't do it.
14. Not designing their data model to lend itself to performant solutions
This is a hard point to quantify. It is typically observed by its effect. If you find yourself writing gnarly queries for relatively simple tasks or that queries for finding out relatively straightforward information is not performant, then you probably have a poor data model.
In some ways this point summarizes all the earlier ones but it's more of a cautionary tale that doing things like query optimisation is often done first when it should be done second. First and foremost you should ensure you have a good data model before trying to optimize the performance. As Knuth said:
Premature optimization is the root of all evil