MariaDB foreign key auto generated index not created for the first column of PK - indexing

i'm facing a question without answer. I can't understand why the auto generated index from the FK creation is not working when the column seems to be the first one of PK, what i mean :
Create a simple schema with :
CREATE TABLE cat (name VARCHAR(255) PRIMARY KEY);
CREATE TABLE dog (name VARCHAR(255) PRIMARY KEY);
CREATE TABLE cat_dog_couple
(
cat_name VARCHAR(255),
dog_name VARCHAR(255),
PRIMARY KEY (cat_name, dog_name),
CONSTRAINT fk__cat_dog_couple__cat_name FOREIGN KEY (cat_name) references cat(name),
CONSTRAINT fk__cat_dog_couple__dog_name FOREIGN KEY (dog_name) references dog(name)
);
These indexes will be generated :
+----------------+------------+------------------------------+--------------+-------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name |
+----------------+------------+------------------------------+--------------+-------------+
| cat_dog_couple | 0 | PRIMARY | 1 | cat_name |
| cat_dog_couple | 0 | PRIMARY | 2 | dog_name |
| cat_dog_couple | 1 | fk__cat_dog_couple__dog_name | 1 | dog_name |
+----------------+------------+------------------------------+--------------+-------------+
Screen show index
I don't really understand why the index fk__cat_dog_couple__cat_name is not created?
Is it a bug ? A technical limitation ? A technical choice ?
Tested on MariaDB 10.4.x and 10.5.x.

Related

How do I enforce referential integrity on a type 6 SCD Dimension table?

I'm having difficulties with designing the Primary and Foreign key relationship between my fact table and a Type 6 SCD Dimension table.
The dimension table has the following definition:
CREATE TABLE DimTable
(
surrogate_key INT,
row_key INT IDENTITY (1,1),
natural_key INT NOT NULL,
current_value INT NOT NULL,
historic_value INT NOT NULL,
is_current BIT NOT NULL,
record_start_date_id INT NOT NULL,
record_end_date_id INT NOT NULL
-- Primary Key
CONSTRAINT pk_dimtable_surrogate_key_row_key PRIMARY KEY (surrogate_key, row_key);
A sample of how the data looks like:
surrogate_key | row_key | natural_key | current_value | historic_value | is_current | record_start_date_id | record_end_date_id
-------------------------------------------------------------------------------------------------------------------------------
121 | 2591227 | 123456 | 20090807 | 20090807 | 0 | 20180807 | 99991231
121 | 2591228 | 123456 | 20140807 | 20090807 | 0 | 20180807 | 99991231
121 | 2591229 | 123456 | 20141107 | 20140807 | 1 | 20180807 | 99991231
122 | 2591230 | 456789 | 20090807 | 20090807 | 1 | 20180807 | 99991231
From my understanding of the wikipedia page, I should be able to enforce Referential integrity through PK/FK relationship, however the master surrogate key is not unique across this table so I don't know how to point the surrogate_id in my fact table to the surrogate_key with a FK constraint.
Is there any way around this limitation, or do I understand the description wrong?
Btw, this is my first time asking a question here, so if anything is unclear or missing please let me know!
EDIT: Column names are generic dummynames. The actual colnames are more descriptive.
I believe you misunderstood the concept of SurrogateKey. Instead the Row_Key attribute here makes more sense of SurrogateKey.
I suggest go one and read books to understand the surrogate key. You may require lot of changes in your process.

SQL: What is does the UNIQUE mean when creating a primary key

I've got a table called students:
+------------+------------+-----------+---------------------+---------------------+
| student_id | first_name | surname | email | reg_date |
+------------+------------+-----------+---------------------+---------------------+
| 1 | Emily | Jackson | emilyj#gmail.com | 2012-10-14 11:14:13 |
| 2 | Daniel | ALexander | daniela#hotmail.com | 2014-08-19 08:08:23 |
| 3 | Sarah | Bell | sbell#gmail.com | 1998-07-04 13:16:32 |
| 4 | Alex | Harte | AHarte#hotmail.com | 1982-06-14 00:00:00 |
+------------+------------+-----------+---------------------+---------------------+
When creating the table:
CREATE TABLE students(
-> student_id INT NOT NULL AUTO_INCREMENT,
-> first_name VARCHAR(30) NOT NULL,
-> surname VARCHAR(50) NOT NULL,
-> email VARCHAR(200) NOT NULL,
-> reg_date DATETIME NOT NULL,
-> PRIMARY KEY (student_id),
-> UNIQUE (email));
What does the 'UNIQUE (email)' mean? Does it mean if the primary key isn't unique, look at the email to see if that's unique instead? Or something different?
Thanks
The UNIQUE keyword creates a unique constraint on the columns that are mentioned in its argument list (in this case, email). It does not interfere with the primary key. It will enforce unique values on the email column, that is, fail with an exception when a row is about to be INSERTed (or UPDATEd) that would collide with an existing row.
A primary key (by default) implies a unique constraint. So as you designate student_id as your primary key, the RDBMS will also automatically maintain unique values in that column for you.
Further reading: http://www.w3schools.com/sql/sql_unique.asp
It allows the engine to use it as an index in queries and enforces it to be unique when a record/s are inserted/updated; throwing a violation of a unique key constraint when an already existing email is inserted/updated.
Example: http://sqlfiddle.com/#!9/7a0aee
More Information: http://dev.mysql.com/doc/refman/5.7/en/partitioning-limitations-partitioning-keys-unique-keys.html

Postgres Object-relation database doesn't seem to function properly

I've defined my tables so:
create table device (
id serial primary key,
manufacturerid integer references manufacturer(id) on delete restrict,
model text,
price real,
usagepros text,
usagecons text
);
create table robot (
numaxes integer,
capacity real,
reach real,
accuracy real,
installmethodid integer references installmethod(id) on delete restrict,
mass real
) inherits (device);
create table robotComplex(
id serial primary key,
name text
);
create table robotComplexDevice(
id serial primary key,
deviceId integer references device(id) on delete restrict,
robotcomplexid integer references robotcomplex(id) on delete cascade
);
etc...
I get the following when running sql commands:
id | manufacturerid | model | price | usagepros | usagecons | numaxes | capacity | reach | accuracy | installmethodid | mass
-----+----------------+-------+-------+-----------+-----------+---------+----------+-------+----------+-----------------+-------
159 | 117 | Robot | 100.3 | OK | NoOK | 6 | 15.3 | 15.4 | 76.1234 | 45 | 100.1
> select * from device;
id | manufacturerid | model | price | usagepros | usagecons
-----+----------------+-------+-------+-----------+-----------
159 | 117 | Robot | 100.3 | OK | NoOK
> select * from robotcomplex;
id | name
----+--------------
27 | Complex
> insert into robotcomplexdevice (deviceid, robotcomplexid) values (159, 27);
ERROR: insert or update on table "robotcomplexdevice" violates foreign key constraint "robotcomplexdevice_deviceid_fkey"
DETAIL: Key (deviceid)=(159) is not present in table "device".
For some reason, even though I've defined the "robot" table to inherit "deivice" table, I can't reference it. Maybe I don't get object-relational database model correctly. But if you can't reference the tables so then what is the point of object-relational model?
This is documented behaviour:
http://www.postgresql.org/docs/current/static/ddl-inherit.html#DDL-INHERIT-CAVEATS

mysql query optimization - join and orderby

I need a little help by one mysql query optimization. It is a simple query but anything is not right and I can't found it :-(
I have 2 tables: products (> 40000 Rows) and product_tags (> 5 mil)
There is a relation betweet the tables 1 -> N . Every prdoduct can have many tags in the table product tags.
I have this simple Query:
EXPLAIN SELECT t.product_id, kwt.tag_id
FROM products AS t, product_tags AS kwt
WHERE 1
AND t.product_id = kwt.product_id
AND kwt.tag_id =11
ORDER BY t.order_date
wchich returns 55 results.
First Situation: if I have this table structure of the tables:
CREATE TABLE IF NOT EXISTS `products` (
`product_id` int(10) unsigned NOT NULL auto_increment,
`product_source_id` smallint(5) unsigned NOT NULL,
`order_date` int(10) unsigned NOT NULL,
PRIMARY KEY (`product_id`),
KEY `order_date` (`order_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
CREATE TABLE IF NOT EXISTS `product_tags` (
`product_tag_id` int(10) unsigned NOT NULL auto_increment,
`tag_id` int(10) unsigned NOT NULL,
`product_id` int(11) NOT NULL,
PRIMARY KEY (`product_tag_id`),
KEY `product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
Then the Explain of the query is this:
+----+-------------+-------+-------+---------------+------------+---------+---------------------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------------+---------+---------------------------+-------+-------------+
| 1 | SIMPLE | t | index | PRIMARY | order_date | 4 | NULL | 45392 | Using index |
| 1 | SIMPLE | kwt | ref | product_id | product_id | 4 | t.product_id | 3 | Using where |
+----+-------------+-------+-------+---------------+------------+---------+---------------------------+-------+-------------+
It is getting all the rows from table products, but there is nothing with temporary table.
Second Situation: If I add an index for the field "tag_id" in product_tags, then the picture is different:
+----+-------------+-------+--------+-------------------+---------+---------+-----------------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------+---------+---------+-----------------------------+------+---------------------------------+
| 1 | SIMPLE | kwt | ref | product_id,tag_id | tag_id | 4 | const | 55 | Using temporary; Using filesort |
| 1 | SIMPLE | t | eq_ref | PRIMARY | PRIMARY | 4 | kwt.product_id | 1 | Using where |
+----+-------------+-------+--------+-------------------+---------+---------+-----------------------------+------+---------------------------------+
Now it selects only 55 rows, what is right, but the query is havy :(
Where is my mistake here ?
Thanks
Nik
this is what i would do:
Read these resources
http://dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html
http://www.xaprb.com/blog/2006/07/04/how-to-exploit-mysql-index-optimizations/
Redesign your system to take advantage of a clustered primary key
Simplified schema:
drop table if exists products;
create table products
(
prod_id int unsigned not null auto_increment primary key,
name varchar(255) not null unique
)
engine = innodb;
drop table if exists tags;
create table tags
(
tag_id mediumint unsigned not null auto_increment primary key,
name varchar(255) not null unique
)
engine = innodb;
drop table if exists product_tags;
create table product_tags
(
tag_id mediumint unsigned not null,
prod_id int unsigned not null,
created_date date not null,
primary key (tag_id, prod_id), -- note the clustered composite index and the order !!
key (prod_id)
)
engine = innodb;
Test the schema
select
pt.tag_id,
pt.prod_id
from
product_tags pt
inner join products p on pt.prod_id = p.prod_id
where
pt.tag_id = 11
order by
pt.created_date
limit 10;
I may even change the product_tags PK to primary key (tag_id, prod_id, created_date) but it all depends on the typical queries you run. You could ofc, just create a non clustered secondary index on created date if you think that's gonna boost performance.
Hope this helps :)

How to change a primary key in SQL to auto_increment?

I have a table in MySQL that has a primary key:
mysql> desc gifts;
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| giftID | int(11) | NO | PRI | NULL | |
| name | varchar(80) | YES | | NULL | |
| filename | varchar(80) | YES | | NULL | |
| effectiveTime | datetime | YES | | NULL | |
+---------------+-------------+------+-----+---------+-------+
but I wanted to make it auto_increment.
The following statement failed. How can it be modified so that it can work? thanks
mysql> alter table gifts modify giftID int primary key auto_increment;
ERROR 1068 (42000): Multiple primary key defined
Leave off the primary key attribute:
ALTER TABLE gifts MODIFY giftID INT AUTO_INCREMENT;
Certain column attributes, such as PRIMARY KEY, aren't exactly properties of the column so much as shortcuts for other things. A column marked PRIMARY KEY, for example, is placed in the PRIMARY index. Futhermore, all columns in the PRIMARY index are given the NOT NULL attribute. (Aside: to have a multi-column primary key, you must use a separate constraint clause rather than multiple PRIMARY KEY column attributes.) Since the column is already in the PRIMARY index, you don't need to specify it again when you modify the column. Try SHOW CREATE TABLE gifts; to see the affects of using the PRIMARY KEY attribute.