I have this table definition.
CREATE TABLE `friendship` (
`fID` bigint(20) NOT NULL AUTO_INCREMENT,
`Part1` bigint(20) NOT NULL DEFAULT '0',
`Part2` bigint(20) NOT NULL DEFAULT '0',
`AddedBy` bigint(11) NOT NULL DEFAULT '0',
`Accepted` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`fID`),
KEY `Part1` (`Part1`,`Part2`),
KEY `Part1_2` (`Part1`),
KEY `Part2` (`Part2`),
KEY `AddedBy` (`AddedBy`),
KEY `Accepted` (`Accepted`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;
Can someone explain me why key "Part1" contains Part1 and Part2, and what are good/bad side of this?
Is it better to use FK on Part1/Part2?
Is there any performance difference using this on MyISAM and InnoDB table?
You have a bad naming convention, for one thing. I would expect the keys to be named:
KEY `Part1_2` (`Part1`,`Part2`),
KEY `Part1` (`Part1`),
In any case, the key that has only Part1 is not needed. The composite key (Part1,Part2) can be used wherever Part1 would be used.
Can someone explain me why key "Part1" contains Part1 and Part2, and
what are good/bad side of this?
As far as I can tell, it's just bad naming. As far as performance and data integrity go, the name here isn't important. It might be troublesome if you later need to drop it by name.
Like Gordon Linoff said, the key named "Part1_2" in your question can be dropped.
Is it better to use FK on Part1/Part2?
There are no unique constraints on either of those columns. MySQL will still let you reference them with a foreign key, but MySQL docs tell you not to do it. (Allowing that was a mistake; it's easier to document it than to fix it.)
Key in MySQL doesn't mean what it means in other SQL dbms. In this CREATE TABLE statement, KEY is a synonym for INDEX; it's not a synonym for UNIQUE or a shorthand for PRIMARY KEY. The only column in this table that can be safely referenced by a foreign key constraint is fID.
Is there any performance difference using this on MyISAM and InnoDB
table?
InnoDB supports row-level locking, transactions, and foreign key constraints. MyISAM doesn't. I'd worry about those differences before I'd think about performance differences. It doesn't matter how fast it runs if your database gives you the wrong answers.
Related
Two tables:
CREATE TABLE `htmlcode_1` (
`global_id` int(11) NOT NULL,
`site_id` int(11) NOT NULL,
PRIMARY KEY (`global_id`),
KEY `k_site` (`site_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `htmlcode_2` (
`global_id` int(11) NOT NULL,
`site_id` int(11) NOT NULL,
PRIMARY KEY (`site_id`,`global_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
which one should be faster for selects and why?
'select * from table where site_id=%s'
The latter table is probably slightly faster for that SELECT query, assuming the table has a nontrivial number of rows.
When querying InnoDB by primary key, the lookup is against the clustered index for the table.
Secondary key lookups require a lookup in the index, then that reveals the primary key value, which is then used to do a lookup by primary key. So this uses two lookups.
The reason to use a PRIMARY KEY is to allow for either quick access OR REFERENTIAL INTEGRITY (CONSTRAINT ... FOREIGN KEY ...)
In your second example, you do not have the proper key for referential integrity if any other table refers to your table. In that case, other operations will be very very slow.
The differences in speed in either case for your particular case should be too small and trivial, but the proper design will dictate the first approach.
The first table represents many "globals" in each "site". That is, a "many-to-one" relationship. But it is the "wrong" way to do it. Instead the Globals table should have a column site_id to represent such a relationship to the Sites table. Meanwhile, the existence of htmlcode_1 is an inefficient waste.
The second table may be representing a "many-to-many" relationship between "sites" and "globals". If this is what you really want, then see my tips . Since you are likely to map from globals to sites, another index is needed.
I have used PHP code to preserve database integrity for years, but now I am switching from MyISAM to InnoDB and thought it might be nice to utilize foreign key constraints, letting the DB carry more of the load. But I want to confirm with the user before doing a cascade, so the constraints would be declared as ON DELETE RESTRICT. When I get the error, I would let the user know that there are dependent records and how many, and if they say, "Sure, delete them," it would be nice to let the database do a cascading delete. Is it possible to tell a specific DELETE statement to go ahead and cascade? I expected an option or something on the DELETE command (e.g. pseudocode DELETE FROM table WHERE ... CASCADE TO child-table), but I didn't see anything.
Example (very standard many-to-many):
CREATE TABLE `person` (
`PersonID` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`FullName` varchar(100) CHARACTER SET utf8mb4 NOT NULL DEFAULT '',
<many other fields>,
PRIMARY KEY (`PersonID`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `category` (
`CategoryID` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`Category` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`CategoryID`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE `percat` (
`PersonID` mediumint(8) unsigned NOT NULL DEFAULT 0,
`CategoryID` mediumint(8) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`PersonID`,`CategoryID`),
FOREIGN KEY (`PersonID`) REFERENCES `person`(`PersonID`) ON DELETE RESTRICT,
FOREIGN KEY (`CategoryID`) REFERENCES `category`(`CategoryID`) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=ascii COLLATE=ascii_bin;
I found How to cascade-delete temporarily or on-demand? but: (a) it's for SQLServer, not MySQL (well, technically I'm using MariaDB 10.2.4, if that makes a difference), so I don't know if I have additional options available to me, and (b) such stored procedure code wouldn't be any simpler than the PHP code I already have (and less visible when I'm developing), so I don't see the point in swapping one for the other.
Short answer: No.
Longer answer:
The answer is simple-minded: FKs are simple-minded. When you ask for more than trivial actions, you are asking for too much of FKs, and you need to build the "business logic" into your application.
Ditto for Triggers.
MySQL (and MariaDB) have always been "lean and mean" compared to the heavy hitters. FKs exist as a check on a feature list "yes, we have FKs, too". So, anything esoteric in the details of FKs are quite likely missing.
Sometimes the syntax is implemented without any real code behind it -- CHECK; INDEX(x DESC). (The latter is finally being implemented in 8.0, but I would estimate the number of use cases to be somewhere around one in a thousand.)
Can creating a UNIQUE index on an Id as shown in the create table below be enough to make the id a Primary Key? TO be more specific, can you say that the table below has a Primary Key?
test` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`role` varchar(32) NOT NULL,
`resources_name` varchar(32) NOT NULL,
`access_name` varchar(32) NOT NULL,
`allowed` int(3) NOT NULL,
UNIQUE KEY `id` (`id`),
UNIQUE KEY `roles_name` (`role`,`resources_name`,`access_name`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8
What query can you use to prove that this has or has no PK?
Logically speaking if a relational table has at least one candidate key enforced in it (minimally unique and non-nullable) then de facto it has a "primary" key. There is no absolute need to single out any one key using a special "primary" label because in principle all keys are equal (historically the term "primary key" used to be used for any and all candidate keys and not just one key per table).
There is a constraint in SQL called a PRIMARY KEY constraint. Logically speaking, the SQL PRIMARY KEY isn't much more than syntactical sugar because the NOT NULL UNIQUE syntax achieves essentially the same thing. Technically the PRIMARY KEY constraint doesn't have to refer to the same thing as the relational concept of a "primary key" but clearly if you are going to designate any one key as primary and if you feel you need a syntactical way of indicating that choice then the PRIMARY KEY constraint is the generally recognised way to do it.
So perhaps the best answer is "it depends". It depends to a large extent on your motivation for defining a primary key in the first place. If you intend to single out one key to developers and users of the database then maybe the NOT NULL UNIQUE syntax won't achieve that for you. If you don't find the need to do that using SQL syntax then maybe NOT NULL UNIQUE is just as good a way to define your keys as the PRIMARY KEY constraint is.
This is either too long or too short for a comment: No.
A primary key and a unique key -- although similar -- are not the same. So, no your table does not have a primary key. The biggest functional difference is that primary keys cannot be NULL whereas unique keys can be.
Primary keys are also typically clustered (if the underlying storage engine supports clustered indexes). This means that the data is actually physically stored on the page in the order of the primary key. Unique keys are just another index with the characteristic of having no repeated values.
EDIT:
Interesting. SHOW COLUMNS documents this behavior:
A UNIQUE index may be displayed as PRI if it cannot contain NULL
values and there is no PRIMARY KEY in the table.
I wasn't aware of this.
I am new to mysql and am working on an online server (MYSQL version 5.1.69) and i have the following table
CREATE TABLE `person_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`person_id` int(11) NOT NULL,
`info_type_id` int(11) NOT NULL,
`info` text NOT NULL,
`note` text,
PRIMARY KEY (`id`),
KEY `idx_pid` (`person_id`),
KEY `person_info_info_type_id_exists` (`info_type_id`)
)
Can someone explain to me what " KEY idx_pid (person_id)," does?
KEY, in MySQL, is an alias for INDEX; you can see this in the pseudo grammar in the CREATE TABLE documentation:
[INDEX|KEY] [index_name] (index_col_name,...)
It represents the definition of an index on a table, and nothing more. Here,
KEY `idx_pid` (`person_id`),
…creates an index named "idx_pid" on the column "person_id". This could have also been written as,
INDEX `idx_pid` (`person_id`),
However, MySQL's SHOW CREATE TABLE command (and other commands) will prefer KEY. It is an unfortunate choice for a keyword here, as it has nothing to do with a “key¹” in the relational databases sense of the word.
¹A key, in relational database theory, is a set of columns that uniquely identify a row.
It means you're creating an index named "idx_pid" on the person_info.person_id column.
This adds an index named idx_pid on the person_id column which speeds up queries using the persond_id as condition.
You can read up on MySQL indexes here.
So I've inherited some django.
The mySQL table is simple enough where parent is NOT a FK relationship just the "Parent" id:
CREATE TABLE `Child` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent` int(10) unsigned NOT NULL,
`name` varchar(255) NOT NULL,
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=24;
But then the originator did this..
class Child(models.Model):
"""Project Child information"""
id = models.AutoField(primary_key=True)
parent = models.ForeignKey(Parent)
name = models.CharField(max_length=255)
class Meta:
managed = False
Admittedly I am NOT a SQL Jockey but I know that a "real" Foreign Key Relationship looks similar to this notice CONSTRAINT...
CREATE TABLE `Child` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `child_63f17a16` (`parent_id`),
CONSTRAINT `parent_id_refs_id_34923e1e` FOREIGN KEY (`parent_id`) REFERENCES `Parent` (`id`)
) ENGINE=InnoDB;
What I want to know is the following:
What problems could I expect to see by this "trickery".
While this appears to work - is it recommended or advised.
Would we be advised to modify the SQL to add in the constraint?
Thanks so much!
Not having an actual constraint might lead to broken references, invalid parents and other sorts of data inconsistencies. I am not a Django expert but I would venture a guess that in most cases Django will still handle the relations fine unless you purposefully add some invalid records.
Normally, if your RDBMS supports foreign key constraints, there is absolutely no reason not to use them, and it could potentially be considered a design flaw to ignore them.
You should consider adding the key constraints. Not only do they give your DBMS a good idea of how to optimize the queries, they also ensure consistency in your data. I am pretty sure Django has a setting somewhere that will automatically generate the SQL to add the key constraints when you run manage.py syncdb
For more information about why you should prefer foreign keys, you should read the MySQL Foreign Key Documentation
Most interestingly:
InnoDB requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist. (This is in contrast to some older versions, in which indexes had to be created explicitly or the creation of foreign key constraints would fail.) index_name, if given, is used as described previously.
Its supposed to be faster ... since you mysql doesn't check the constraint before adding a row in the child table.
But with the foreign key, it would make your life easier since you can use the on update and on delete.
I'd go with the constraint.