I am a mysql newbie. I have a question about the right thing to do for create table ddl. Up until now I have just been writing create table ddl like this...
CREATE TABLE file (
file_id mediumint(10) unsigned NOT NULL AUTO_INCREMENT,
filename varchar(100) NOT NULL,
file_notes varchar(100) DEFAULT NULL,
file_size mediumint(10) DEFAULT NULL,
file_type varchar(40) DEFAULT NULL,
file longblob DEFAULT NULL,
CONSTRAINT pk_file PRIMARY KEY (file_id)
);
But I often see people doing their create table ddl like this...
CREATE TABLE IF NOT EXISTS `etags` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`item_code` varchar(100) NOT NULL,
`item_description` varchar(500) NOT NULL,
`btn_type` enum('primary','important','success','default','warning') NOT NULL DEFAULT 'default',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;
A few questions...
What difference do the quotes around the table name and column names make?
Is it good practice to explicitly declare the engine and character set? What engine and character sets are used by default?
thanks
There's no difference. Identifiers (table names, column names, et al.) must be enclosed in the backticks if they contain special characters or are reserved words. Otherwise, the backticks are optional.
Yes, it's good practice, for portability to other systems. If you re-create the table, having the storage engine and character set specified explicitly in the CREATE TABLE statement means that your statement won't be dependent on the settings of the default_character_set and default-storage-engine variables (these may get changed, or be set differently on another database.)
You can get your table DDL definition in that same format using the SHOW CREATE TABLE statement, e.g.
SHOW CREATE TABLE `file`
The CREATE TABLE DDL syntax you are seeing posted by other users is typically in the format produced as output of this statement. Note that MySQL doesn't bother with checking whether an identifier contains special characters or reserved words (to see if backticks are required or not), it just goes ahead and wraps all of the identifiers in backticks.
With backticks, reserved words and some special characters can be used in names.
It's simply a safety measure and many tools automatically add these.
The default engine and charset can be set in the servers configuration.
They are often (but not always) set to MyISAM and latin1.
Personally, I would consider it good practice to define engine and charset, just so you can be certain what you end up with.
Related
Many tables will do fine using CHARACTER SET ascii COLLATE ascii_bin which will be slightly faster. Here's an example:
CREATE TABLE `session` (
`id` CHAR(64) NOT NULL,
`created_at` INTEGER NOT NULL,
`modified_at` INTEGER NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT FOREIGN KEY (`user_id`) REFERENCES `user`(`id`)
) CHARACTER SET ascii COLLATE ascii_bin;
But if I were to join it with:
CREATE TABLE `session_value` (
`session_id` CHAR(64) NOT NULL,
`key` VARCHAR(64) NOT NULL,
`value` TEXT,
PRIMARY KEY (`session_id`, `key`),
CONSTRAINT FOREIGN KEY (`session_id`) REFERENCES `session`(`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
what's gonna happen? Logic tells me it should be seamless, because ASCII is a subset of UTF-8. Human nature tells me I can expect anything from a core dump to a message Follow the white rabbit. appearing on my screen. ¯\_(ツ)_/¯
Does joining ASCII and UTF-8 tables add overhead?
Yes.
If you do
SELECT whatever
FROM session s
JOIN session_value v
ON s.id = v.session_id
the query engine must compare many values of id and session_id to satisfy your query.
If id and session_id have exactly the same datatype, the query planner will be able to exploit indexes and fast comparisons.
But if they have different character sets, the query planner must interpret your query as follows.
... JOIN session_value v
ON CONVERT(s.id USING utf8mb4) = v.session_id
When a WHERE or ON condition has the form f(column) it makes the query non-sargable: it prevents efficient index use. That can hammer query performance.
In your case, similar performance problems will occur when you insert rows to session_value: the server must do the conversion to check your foreign key constraint.
If these tables are going to production, you'd be very wise to use the same character set for these columns. It's much easier to fix this when you have thousands of rows than when you have millions. Seriously.
What makes a SQL statement sargable?
Why not UTF-8 all the way through? Having ASCII tables is usually a mistake, a sign you forgot to set the encoding on something. Using a singular encoding vastly simplifies your internal architecture.
Encoding is only relevant if and when you have CHAR, VARCHAR or TEXT columns.
If you have a column of that type then it's worth setting it as UTF8MB4 by default.
Looking at examples of a standard SQL layout I see this:
CREATE TABLE IF NOT EXISTS siteUser (
id int(11) AUTO_INCREMENT PRIMARY KEY,
email varchar(64) NOT NULL UNIQUE KEY,
password varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT;
What is th purpose of the "DEFAULT" at the end of specifying the engine? Is there any need for it? I tried to find an explanation of it on tutorial websites but I didn't have any luck.
James
Are you sure it's not an error? I can't find any reference of a default parameter for the database engine in a create table statement. Also, your create table statement fails in SQLFiddle.com in both MySQL 5.1 and 5.5.
I think you might have misinterpreted the default as being part of the engine clause, while actually it was part of a charset or collate clause. For instance, this is valid, since default is an optional keyword in front of the charset clause:
CREATE TABLE IF NOT EXISTS siteUser (
id int(11) AUTO_INCREMENT PRIMARY KEY,
email varchar(64) NOT NULL UNIQUE KEY,
password varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET = utf8;
I guess the charset and collate clauses can have the default keyword (which is practically meaningless by the way), because they specify a default charset or collation, but there is still a possibility to override this per column.
For a storage engine this would be silly. There is no 'default' storage engine for a single table. There is only one. Also, it wouldn't make sense if it would set the default for the whole database. Why would that be an option in a create table statement?
It is used to set ENGINE=InnoDB as the default engine. So one way is to either remove the Engine = INNODB from your create table statement
CREATE TABLE IF NOT EXISTS siteUser (
id int(11) AUTO_INCREMENT PRIMARY KEY,
email varchar(64) NOT NULL UNIQUE KEY,
password varchar(255) NOT NULL
)
DEMO
Or the other way which GolezTrol has suggested:
CREATE TABLE IF NOT EXISTS siteUser (
id int(11) AUTO_INCREMENT PRIMARY KEY,
email varchar(64) NOT NULL UNIQUE KEY,
password varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT charset = utf8;
DEMO
From the Manual: InnoDB as the Default MySQL Storage Engine
In previous versions of MySQL, MyISAM was the default storage engine.
In our experience, most users never changed the default settings. With
MySQL 5.5, InnoDB becomes the default storage engine. Again, we expect
most users will not change the default settings. But, because of
InnoDB, the default settings deliver the benefits users expect from
their RDBMS: ACID Transactions, Referential Integrity, and Crash
Recovery.
However if you want to make the INNODB as your deafult engine then there is one other way:
Under [mysqld] section in your ini file, add:
default-storage-engine = innodb
It is there in /etc/my.cnf
The normal examples I see for creating a table go like this:
CREATE TABLE supportContacts
(
id int auto_increment primary key,
type varchar(20),
details varchar(30)
);
However an example I'm looking at does it like this:
CREATE TABLE IF NOT EXISTS `main`.`user` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`user_password_hash` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`user_email` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_name` (`user_name`),
UNIQUE KEY `user_email` (`user_email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Specifically, on the create table like it is specifying the database and the new table and surrounding them in `'s. What is the reasoning for this, and does one way have an advantage over the other?
The backticks are escape characters needed when identifiers contain special characters (such as spaces) or are reserved words (such as group or order).
Otherwise, they are not needed, and I do not think they are needed for any of the identifiers in this create table statement.
My personal preference is that over-use of escape characters is a bad thing:
They make the query harder to read, because there are unnecessary characters everywhere.
They make it harder to write the query. I imagine the backtick key on people who do this alot starts to break.
They encourage (or at least do not discourage) the use of "difficult" identifers.
They make it more difficult to move code between databases. (MySQL is one of the few databases that use backticks as an escape character.)
Of course, some people have different opinions on some of these points (although I think the second and fourth points are more truth than opinion).
Backticks are used to escape table and column names.
You can do this to use keywords. If you want to name a column from for instance then you need the backticks. Otherwise the the DB interprets this a keyword.
Or if you want spaces in your table name like my table which BTW I recommend not to do.
In SQL Server you would use [] to escape the names.
I am just starting with SQL syntax, and am trying to create a table.
Here is my error:
#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'CONSTRAINT uc_people_2nd UNIQUE (lastName,firstName), ) ENGINE = INNODB' at line 7
And here is my SQL:
CREATE TABLE `people` (
`_id` INT NOT NULL AUTO_INCREMENT,
`lastName` TEXT NOT NULL,
`firstName` TEXT NOT NULL,
`JSON` TEXT NOT NULL,
PRIMARY KEY(_id)
CONSTRAINT uc_people_2nd UNIQUE (lastName,firstName),
) ENGINE = INNODB;
I tried this in NodeDB (which I am developing in), and then PHPMyAdmin.
Fix the comma and make the names varchar():
CREATE TABLE `people` (
`_id` INT NOT NULL AUTO_INCREMENT,
`lastName` varchar(255) NOT NULL,
`firstName` varchar(255) NOT NULL,
`JSON` TEXT NOT NULL,
PRIMARY KEY(_id),
CONSTRAINT uc_people_2nd UNIQUE (lastName, firstName)
) ENGINE = INNODB;
This works on SQL Fiddle.
Note that you don't have to give a unique constraint a name. You can also drop the constraint keyword, so the following works just fine:
UNIQUE (lastName, firstName)
EDIT:
The text data type is described here on the page with other "large-objects". These are special types that are arbitrarily long (think megabytes). They have limits when used in indexes. In particular, they need a length prefix. So, you cannot declare that a text column is unique. Only that they are unique in the first N characters (up to about 1000).
For names, that is way overkill. MySQL supports string types of various sorts. The most useful is varchar(). These are appropriate for a name field. They can be used with indexes easily. And MySQL supports a plethora of functions on them.
In other words, if you do not know what text is, you do not need it. Learn about and use varchar() and char() (or nvarchar() and nchar() if you need national character set support). Forget about text. One day if you need it, you'll rediscover it.
I have just a little information about MySql. I just need to create a database to store some score of a videogame, taken from all over the world. (The game will be in every available store, also Chinese etc.)
I'm worried about the charset. Db schema's will be similar to (pseudocode):
leaderboard("PhoneId" int primary key, name varchar(50), score smallint);
What will happen if a chinese guy will put his score with a name with that characters? Should I specify something into db creation script?
create database if not exists "test_db";
create table if not exists "leaderboard" (
"phoneid" integer unsigned NOT NULL,
"name" varchar(20) NOT NULL, -- Gestione errori per questo
"score" smallint unsigned NOT NULL default 0,
"timestamp" timestamp NOT NULL default CURRENT_TIMESTAMP,
PRIMARY KEY ("phoneid")
);
UTF8 is your obvious choice.
For details on UTF8 and MySQL integration, you can go through the Tutorial pages:
http://dev.mysql.com/doc/refman/5.0/en/charset-unicode-utf8.html
http://dev.mysql.com/doc/refman/5.0/en/charset-unicode.html
There are certain things that needs to be kept in mind while using the UTF8 charset in any database. For example, To save space with UTF-8, use VARCHAR instead of CHAR. Otherwise, MySQL must reserve three bytes for each character in a CHAR CHARACTER SET utf8 column because that is the maximum possible length.
Similarly you should analyze other performance constraints and design your database.