I have the following table with 1,000,000+ records:
CREATE TABLE `products` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`description` text,
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
What I'd like to do is be able to fetch products with null description quickly - forget about empty string.
If I add a key by description, the whole description will be indexed and I don't want such a big index. I could indeed do:
ALTER TABLE products ADD KEY has_description (description(1));
This will create an index with only the first character. This is much better than having a "complete" index, but I'd like to know if there's a way to create a proper index - e.g. a boolean index, true/false depending on the product having a description or not respectively.
Additional requirement is not adding a new column with this value - that is trivial, but it's duplicated information I don't want to have in the table.
Already tried stuff like
ALTER TABLE products ADD KEY has_description (description IS NULL);
... but didn't work.
Can this be done at all?
You can only have Index on existing fields.
The answer is: no way
But you can add another Field (and Index for that) containing the description state (empty or not).
Use Insert and Update trigger to have that field always synced with description data.
Related
What's the difference between this code:
CREATE TABLE samples (
sampleid INT(11) NOT NULL AUTO_INCREMENT,
sampledate DATE NOT NULL,
location VARCHAR(25) NOT NULL,
PRIMARY KEY (sampleid)
)
ENGINE=InnoDB;
and this:
CREATE TABLE samples (
sampleid INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
sampledate DATE NOT NULL,
location VARCHAR(25) NOT NULL,
)
ENGINE=InnoDB;
code?
So a separate PRIMARY KEY statement or as part of a column definition. Same question for UNIQUE INDEX and UNIQUE keyword in column definition.
The second syntax is merely a shortcut allowing you to specify the column and add an index on it in a single clause.
This works out fine in cases where you simply want to create a column and add an index on it.
You'll need to use the first syntax if you want to do something more complicated, such as adding an index based on multiple columns rather than a single column, or if you are adding or changing an index on an existing column; that is, you are not creating the column and the index on it at the same time.
MySQL allows uses the PRIMARY KEY directive to allow you to set the Primary Key dynamically. Supplying PRIMARY KEY as an argument to the constructor can only be called on creating the column. PRIMARY KEY(X), PRIMARY KEY(Y), PRIMARY KEY(Z) allows for changing the primary keys on subsequent queries.
The way I see it is.. The first method is used to create composite keys. While the second method (more readable to me) is primarily used if there is only primary key in the table.
The second method cannot be used if you want to implement composite key
There are many ways to skin a cat and above 2 examples are just 2 of them. They are identical. There's no difference.
They are literally the same. Here is a quick site that shows you the different ways (3) to do it. http://www.java2s.com/Code/SQL/Key/Defineanduseprimarykey.htm
I see two ways it is done:
Method 1:
CREATE TABLE IF NOT EXISTS `sample` (
`sample_id` tinyint(2) NOT NULL AUTO_INCREMENT,
`description` varchar(32) NOT NULL,
`parent_id` int(10) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`sample_id`)
) ENGINE=InnoDB;
ALTER TABLE sample ADD CONSTRAINT parent_id FOREIGN KEY (parent_id) REFERENCES parent_tbl(parent_id);
Method 2:
CREATE TABLE IF NOT EXISTS `sample` (
`sample_id` tinyint(2) NOT NULL AUTO_INCREMENT,
`description` varchar(32) NOT NULL,
`parent_id` int(10) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`sample_id`),
Foreign Key (parent_id) references parent_tbl(parent_id)
) ENGINE=InnoDB;
Which way is better or when to use one over the other?
If you need to add a foreign key to an existing table, use method 1, if you are creating the schema from scratch use method 2.
There isn't a best way, they do the same thing.
The first gives you more flexibility.
1) You are required to use the first method if you create the tables in an order such that a referenced table is created after its referencing table. If you have loops in your references then there may not be a way to avoid this. If there are no loops then there exists an order where all referenced tables are created before their referenced tables, but you may not want to spend time figuring out what that order is and rearranging your scripts.
2) It's not always the case that you know exactly what indexes you will need when you create the table. When you create indexes it is usually a good idea to measure the performance gain on some real data, and perhaps try multiple different indexes to see which works better. For this strategy to work you need to first create the table, insert some data and then you need to be able to modify the indexes for testing. Dropping and recreating the table is not as practical as ALTER TABLE in this situation.
Other than that there isn't really any difference and if you are starting from nothing there is no particular reason to favour one over the other. The resulting index is the same either way.
The end products are indistinguishable.
For clarity (it's nice to see the constraint explictly stand on it's own), I might advocate for the first.
For succinctness (saying the same thing in 1 statement vs 2), I'd might advocate for the second.
So I have a class that creates a table to be populated with data. Right now I have all the column names the same (product_name, date, etc). I noticed that when I view my tables in Webmin that there is only one index named "product_date" despite the fact that there are, supposedly, two tables using the index. I don't think this can be good.
My question is whether or not this will cause a conflict in the future? I don't want to populate the tables with thousands of rows if I'm only going to need to restructure everything later. I can't imagine that I'm the first to encounter this... maybe I'm just misinformed on how indexes work/webmin displays indexes and being overly paranoid.
(edit)
In response to one comment below, here are the results of SHOW CREATE TABLE tablename:
c_1 | CREATE TABLE c_1 (
p_id int(11) NOT NULL auto_increment,
nm varchar(100) NOT NULL,
m_name text NOT NULL,
PRIMARY KEY (p_id),
KEY nm (nm),
FULLTEXT KEY m_name (m_name)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
c_2 | CREATE TABLE c_2 (
p_id int(11) NOT NULL auto_increment,
ne varchar(100) NOT NULL,
m_name text NOT NULL,
PRIMARY KEY (p_id),
KEY nm (nm),
FULLTEXT KEY metaphone_name (m_name)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
Note that all the indexes on equivalent columns are named the same way.
If it's an index per table, no problem
If I understand your question correctly (a big if), you must create an index for each table. Indexes do not cover more than one table until you get into advanced concepts like indexed/materialized views, which I don't think MySQL handles.
I have a table in mysql called advertisements, in which there is an entity called position , now while creating the table i have defined the position entity as unique so that i don't get the duplicated entry into the table, now i want to remove that Unique attribute from the table entity Position in the table advertisement.
what is the mysql syntax for this?
CREATE TABLE `advertisements` (
`id` int(11) NOT NULL auto_increment,
`pos` smallint NOT NULL UNIQUE,
PRIMARY KEY (`id`)
);
Above is the Code, can someone please make a syntax for me drop that Unique Attribute attached to the pos entity.
Your unique index have some name, use:
ALTER TABLE `advertisements` DROP INDEX `index_name_on_position`
Use:
SHOW INDEXES IN advertisements
To obtain its name.
I have a simple table set up with two columns, each column is a key value. the values stored in each field are varchar(45) representing an email address and a keyword. It is possible that the information collected may duplicate itself as it is related to site browsing data collection. To avoid duplicate entries, I used tried to use INSERT IGNORE into, REPLACE into, and finally I'm trying the following:
insert into <table name> (user_email, key_token) values ('<email>#<this>.com', 'discountsupplies') on duplicate key update user_email='<email>#<this>.com',key_token='discountsupplies';
but I am still seeing duplicate records being inserted into the table.
The SQL that generated the table:
DROP TABLE IF EXISTS `<database name>`.`<table name>` ;
CREATE TABLE IF NOT EXISTS `<database name>`.`<table name>` (
`user_email` VARCHAR(45) NOT NULL ,
`key_token` VARCHAR(45) NOT NULL,
PRIMARY KEY (`user_email`, `key_token`) )
ENGINE = InnoDB;
While I saw several questions that were close to this one, I did not see any that addressed why this might be happening, and I'd like to figure out what I'm not understanding about this behavior. Any help is appreciated.
As an addendum, After adding the UNIQUE KEY statements, I went back and tried both REPLACE and INSERT IGNORE to achieve my goal, and none of these options is excluding duplicate entries.
Also adding: UNIQUE INDEX (user_email, key_token)
doesn't seem to help either.
I'm going to do this check via a manual look-up routine until I can figure this out. If I find an answer I'll be happy to update the post.
Added Unique Index lines below the original create table statement -
-- -----------------------------------------------------
-- Table `<db name>`.`<table name>`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `<db name>`.`<table name>` ;
CREATE TABLE IF NOT EXISTS `<db name>`.`<table name>` (
`user_email` VARCHAR(45) NOT NULL ,
`key_token` VARCHAR(45) NOT NULL,
PRIMARY KEY (`user_email`, `key_token`),
UNIQUE KEY (user_email),
UNIQUE KEY (key_token)
)
ENGINE = InnoDB;
CREATE UNIQUE INDEX ix_<table name>_useremail on `<db name>`.`<table name>`(user_email);
CREATE UNIQUE INDEX ix_<table name>_keytoken on `<db name>`.`<table name>`(key_token);
it seems to be ok (no errors when creating tables during the source step), but I'm still getting duplicates when running the on duplicate query.
You have a composite primary key on both columns.
This means that it's the combination of the fields is UNIQUE, not each field as is.
Thes data are possible in the table:
1#example.com 1
2#example.com 1
2#example.com 2
, since no combination of (user_email, key_token) repeats in the table, while user_email and key_token as themselves can repeat.
If you want each separate column to be UNIQUE, define the UNIQUE constraints on the fields:
CREATE TABLE IF NOT EXISTS `<database name>`.`<table name>` (
`user_email` VARCHAR(45) NOT NULL ,
`key_token` VARCHAR(45) NOT NULL,
PRIMARY KEY (`user_email`, `key_token`),
UNIQUE KEY (user_email),
UNIQUE KEY (key_token)
)
ENGINE = InnoDB;
Update
Having duplicates in a column marked as UNIQUE would be a level 1 bug in MySQL.
Could you please run the following queries:
SELECT user_email
FROM mytable
GROUP BY
user_email
HAVING COUNT(*) > 1
SELECT key_token
FROM mytable
GROUP BY
key_token
HAVING COUNT(*) > 1
and see if they return something?
PRIMARY KEY (user_email,key_token) means a combination of both will be unique but if you also want individual email and key_tokens to be unique you have to use UNIQUE seperately for each column..
PRIMARY KEY ('user_email', 'key_token'),
UNIQUE KEY (user_email),
UNIQUE KEY (key_token)
final solution for now: query table to get list of key_tokens by user_email, test current key_token against list entries, if found don't insert.
Not optimal or pretty, but it works....
To me it looks like you selected composite Primary Key solely for performance reasons where it should be an index like so
CREATE TABLE IF NOT EXISTS `<database name>`.`<table name>` (
`user_email` VARCHAR(45) NOT NULL ,
`key_token` VARCHAR(45) NOT NULL,
PRIMARY KEY (`user_email`),
INDEX (`user_email`, `key_token`)
)
Of course if you are concerned about getting a duplicate key_token you'll still need a unique index.
Sorry I'm awfully late to reply, but perhaps someone will stumble on this like I have :)