I am trying to convert a table from MyISAM into InnoDB, this is the definition and I am getting error #1075 - Incorrect table definition; there can be only one auto column and it must be defined as a key
The table has an AutoIncrement value and the field is indexed and it works with MyISAM. I am new to InnoDB so it might be a dumb question
CREATE TABLE `cart_item` (
`cart_id` int(10) unsigned NOT NULL DEFAULT '0',
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`design_number` int(10) unsigned NOT NULL,
`logo_position_id` smallint(5) unsigned NOT NULL,
`subst_style_id` varchar(10) DEFAULT NULL,
`style_id` varchar(10) NOT NULL DEFAULT '',
`subst_color_id` smallint(5) unsigned DEFAULT NULL,
`color_id` smallint(5) unsigned NOT NULL,
`size_id` smallint(5) unsigned NOT NULL,
`qty` mediumint(8) unsigned NOT NULL,
`active` enum('y','n') NOT NULL DEFAULT 'y',
`date_last_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`last_modified_by_id` mediumint(5) unsigned NOT NULL,
`date_last_locked` datetime DEFAULT NULL,
`last_locked_by_id` smallint(5) unsigned NOT NULL,
`date_added` datetime NOT NULL,
`subsite_logo_group_id` int(11) NOT NULL,
`bundle` varchar(32) NOT NULL,
`color_stop_1` varchar(4) DEFAULT NULL,
PRIMARY KEY (`cart_id`,`id`),
KEY `color_id` (`color_id`),
KEY `style_id` (`style_id`),
KEY `size_id` (`size_id`),
KEY `design_number` (`design_number`),
KEY `subsite_logo_group_id` (`subsite_logo_group_id`),
KEY `date_added` (`date_added`),
KEY `bundle` (`bundle`)
) ENGINE=InnoDB
What you were doing on the MyISAM table, cannot be done with InnoDB. See my answer on a (similar) problem: creating primary key based on date
MySQL docs, in the Using AUTO_INCREMENT section, explain it:
For MyISAM tables you can specify AUTO_INCREMENT on a secondary column in a multiple-column index. In this case, the generated value for the AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1 WHERE prefix=given-prefix. This is useful when you want to put data into ordered groups.
You may get similar behaviour in InnoDB but not with AUTO_INCREMENT. You'll have to use either some fancy trigger or a stored procedure for your Inserts that will take care of the (per cart_id) auto-increment.
You have a composite PRIMARY KEY defined on (cart_id, id), but the AUTO_INCREMENT requires an index on id alone. You can add a KEY for it (not a primary key, but just a plain index):
KEY `idx_id` (`id`)
I question the use of the composite PK on (cart_id, id) though, since id is alone a unique value by definition. Perhaps you should make id the PK, and create a separate index across the combination.
PRIMARY KEY (`id`),
KEY (`cart_id`, `id`)
It doesn't even need to be specified as UNIQUE because the AUTO_INCREMENT can't be repeated anyway. There is no way to violate uniqueness on the combination (cart_id, id).
AUTO_INCREMENT columns should be define as key, as what the error implies.
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
and set UNIQUE on the two column instead of primary key
UNIQUE (`cart_id`,`id`),
SQLFiddle Demo
Related
I have an innoDB table named "transaction" with ~1.5 million rows. I would like to partition this table (probably on column "gas_station_id" since it is used a lot in join queries) but I've read in MySQL 5.7 Reference Manual that
All columns used in the table's partitioning expression must be part of every unique key that the table may have, including any primary key.
I have two questions:
The column "gas_station_id" is not part of unique key or primary key. How could I partition this table then?
even if I could partition this table, I am not sure which partitioning type would be better in this case? (I was thinking about LIST partitioning (we have about 40 different(distinct) gas stations) but I am not sure since there will be only one value in each list partition like the following :
ALTER TABLE transaction
PARTITION BY LIST(gas_station_id)
( PARTITION p1 VALUES IN (9001),
PARTITION p2 VALUES IN (9002),.....)
I tried partitioning by KEY, but I receive the following error (I think because id is not part of all unique keys..):
#1053 - a UNIQUE INDEX must include all columns in the table's partitioning function
This is the structure of the "transaction" table:
EDIT
and this is what SHOW CREATE TABLE shows:
CREATE TABLE `transaction` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`terminal_transaction_id` int(11) NOT NULL,
`fuel_terminal_id` int(11) NOT NULL,
`fuel_terminal_serial` int(11) NOT NULL,
`xboard_id` int(11) NOT NULL,
`gas_station_id` int(11) NOT NULL,
`operator_id` varchar(16) NOT NULL,
`shift_id` int(11) NOT NULL,
`xboard_total_counter` int(11) NOT NULL,
`fuel_type` tinyint(2) NOT NULL,
`start_fuel_time` int(11) NOT NULL,
`end_fuel_time` int(11) DEFAULT NULL,
`preset_amount` int(11) NOT NULL,
`actual_amount` int(11) DEFAULT NULL,
`fuel_cost` int(11) DEFAULT NULL,
`payment_cost` int(11) DEFAULT NULL,
`purchase_type` int(11) NOT NULL,
`payment_ref_id` text,
`unit_fuel_price` int(11) NOT NULL,
`fuel_status_id` int(11) DEFAULT NULL,
`fuel_mode_id` int(11) NOT NULL,
`payment_result` int(11) NOT NULL,
`card_pan` varchar(20) DEFAULT NULL,
`state` int(11) DEFAULT NULL,
`totalizer` int(11) NOT NULL DEFAULT '0',
`shift_start_time` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `terminal_transaction_id` (`terminal_transaction_id`,`fuel_terminal_id`,`start_fuel_time`) USING BTREE,
KEY `start_fuel_time_idx` (`start_fuel_time`),
KEY `fuel_terminal_idx` (`fuel_terminal_id`),
KEY `xboard_idx` (`xboard_id`),
KEY `gas_station_id` (`gas_station_id`) USING BTREE,
KEY `purchase_type` (`purchase_type`) USING BTREE,
KEY `shift_start_time` (`shift_start_time`) USING BTREE,
KEY `fuel_type` (`fuel_type`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1665335 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
Short answer: Don't use PARTITION. Let's see the query to help speed it up.
Long answer:
1.5M rows is only marginally big enough to consider partitioning.
PARTITION BY LIST is probably useless for performance.
You have not given enough info to give you answers other that vague hints. Please provide at least SHOW CREATE TABLE and the slow SELECT.
It is possible to add the partition key onto the end of the PRIMARY or UNIQUE key; you will lose the uniqueness test.
Don't index a low-cardinality column; it won't be used.
More on PARTITION
Can someone please explain the cause for the following error, 'Can't create table 'Activities' (errno: 150)'
I'm under the understading that the data types and lengths have to be the same, does is have anything to do with the auto increment?
Create Table `LinkMemberActivity` (
`LinkID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`MID` int(11) unsigned NOT NULL,
`AID` int(11) unsigned NOT NULL,
PRIMARY KEY (`LinkID`),
FOREIGN KEY (`MID`) REFERENCES Members(`MID`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;
)
CREATE TABLE `Activities` (
`AID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`Name` varchar(25) DEFAULT NULL,
`MaxCapacity` int(25) DEFAULT NULL,
`StartTime` time DEFAULT NULL,
`EndTime` time DEFAULT NULL,
PRIMARY KEY (`AID`),
FOREIGN KEY (`AID`) REFERENCES LinkMemberActivity(`AID`))
ENGINE=InnoDB DEFAULT CHARSET=latin1 );
You are trying to make a primary key column a foreign key dependent field. This is not only unusual but makes no sense in a datamodel, unless it is part of a composite key. Common practice has a column foreign key dependent on another tables primary key. Not sure what reasons you have for the way you designed your datamodel this way, but you can fix this problem by creating a not null autoincrement column named ID and make this column the primary key. Next remove autoincrement from aid.
I have a table with many many duplicated row, I cannot create a unique value for the blob field, because is too large.
How can I find and delete the duplicate rows where the blob field (answer) is duplicated?
This is the table structure :
CREATE TABLE `answers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_question` int(11) NOT NULL,
`id_user` int(11) NOT NULL,
`answer` blob NOT NULL,
`language` varchar(2) NOT NULL,
`datetime` datetime NOT NULL,
`enabled` int(11) NOT NULL DEFAULT '0',
`deleted` int(11) NOT NULL DEFAULT '0',
`spam` int(11) NOT NULL DEFAULT '0',
`correct` int(11) NOT NULL DEFAULT '0',
`notification_send` int(11) NOT NULL DEFAULT '0',
`correct_notification` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `id_question` (`id_question`),
KEY `id_user` (`id_user`),
KEY `enabled` (`enabled`)
) ENGINE=InnoDB AUTO_INCREMENT=1488 DEFAULT CHARSET=utf8mb4
probable you can use prefix of the column by substr() or left() and compare. How much size you want to take that depends on your data distribution or prefix uniqueness of the column data.
for uniqueness check you can fire the below query if the
select count(distinct left(answer, 128))/count(*), count(distinct left(answer, 256))/count(*) from answers.
This will provide you selectivity or data distribution in your column. suppose 128 gives you answer as 1 i.e. all unique if you take first 128 bytes then choose that amount of data from each row and work. Hope it helps.
We have a 'visitor' tracking schema going on - that when pushed, seems to be causing some strain on the DB server.
VISITORS table identifies unique users by a HASH (current records 310,000). A search is performed on the hash, and if not found, it is added. The ID is needed for the following two tables
CREATE TABLE visitors (
id int(10) UNSIGNED NOT NULL auto_increment,
ip varchar(25) NOT NULL,
hash varchar(64) NOT NULL,
first_visit varchar(32) NOT NULL,
created_at datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE visitors ADD UNIQUE INDEX (hash);
ALTER TABLE visitors ADD INDEX (created_at);
VISITOR_VISITS table identifies when a user visited only when we can identify some referral sources (current count 142,000). A search is performed looking for the visitor_id, type and visit_date. If there is nothing found - it is added. The ID is used in the following table.
CREATE TABLE visitor_visits (
id int(10) UNSIGNED NOT NULL auto_increment,
visitor_id int(10) UNSIGNED NOT NULL,
source varchar(64) NULL DEFAULT NULL DEFAULT NULL,
medium varchar(64) NULL DEFAULT NULL,
campaign varchar(256) NULL DEFAULT NULL,
page varchar(32) NULL DEFAULT NULL,
landing varchar(32) NULL DEFAULT NULL,
type enum('fundraiser_view') NULL DEFAULT NULL,
visit_date date NOT NULL default '0000-00-00',
created_at datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE visitor_visits ADD UNIQUE INDEX (visitor_id,type,visit_date);
ALTER TABLE visitor_visits ADD CONSTRAINT FK_visits_visitor_id FOREIGN KEY (visitor_id) REFERENCES visitors(id);
PAGE_VIEWS logs individual page views (not all pages, just pages we are tracking). It can be linked to a visitor and can reference a visitor_visit (current count 2.4million -- reason it is higher is we started micro-visitor logging after logging individual pages). An insert/on duplicate query is used to add the record to this based on the view_date for the identified user. Since the ID is not needed, a pure lookup query isnt required
CREATE TABLE page_views (
id int(10) UNSIGNED NOT NULL auto_increment,
page_id int(10) UNSIGNED NOT NULL,
current_donations decimal(10,2) NOT NULL DEFAULT 0,
ip varchar(25) NOT NULL,
hash varchar(32) NOT NULL,
visitor_id int(10) UNSIGNED NULL DEFAULT NULL AFTER,
visitor_visit_id int(10) UNSIGNED NULL DEFAULT NULL AFTER,
page_views int(10) UNSIGNED NOT NULL DEFAULT 0,
widget_views int(10) UNSIGNED NOT NULL DEFAULT 0,
view_date date NOT NULL,
viewed_at datetime NOT NULL default '0000-00-00 00:00:00',
created_at datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE page_views ADD UNIQUE INDEX (page_id,view_date,visitor_id,hash);
ALTER TABLE page_views ADD INDEX (visitor_id);
ALTER TABLE page_views ADD INDEX (visitor_visit_id);
ALTER TABLE page_views ADD CONSTRAINT FK_page_views_page_id FOREIGN KEY (page_id) REFERENCES pages(id);
ALTER TABLE page_views ADD CONSTRAINT FK_page_views_visitor_id FOREIGN KEY (visitor_id) REFERENCES visitors(id);
ALTER TABLE page_views ADD CONSTRAINT FK_page_views_visit_id FOREIGN KEY (visitor_visit_id) REFERENCES visitor_visits(id);
Last week, our site got a inflow of people due to a news article, and this visitor identifying rall bottlenecked performance. I am wondering if there is an obvious optimization in there. Could it be the foreign key constraints ? Over indexing? Need for better indexing?
Try this ::
1) Index on varchar doesn't much improve the performance.
2) Try to partition the table, on a date range.
You didn't tell us what is bottlenecking your database, so I just guess it's InnoDB concurrent writes. If it isn't so and the problem is only with SELECTs (which I doubt), you should show us the exact queries. You could try to reduce the write performance hit by creating a staging table and then bulk-moving stuff from in to the main table:
CREATE TABLE page_views_tmp (
id int(10) UNSIGNED NOT NULL auto_increment,
page_id int(10) UNSIGNED NOT NULL,
current_donations decimal(10,2) NOT NULL DEFAULT 0,
ip varchar(25) NOT NULL,
hash varchar(32) NOT NULL,
visitor_id int(10) UNSIGNED NULL DEFAULT NULL AFTER,
visitor_visit_id int(10) UNSIGNED NULL DEFAULT NULL AFTER,
page_views int(10) UNSIGNED NOT NULL DEFAULT 0,
widget_views int(10) UNSIGNED NOT NULL DEFAULT 0,
view_date date NOT NULL,
viewed_at datetime NOT NULL default '0000-00-00 00:00:00',
created_at datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (id)
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
And then, once per a couple of seconds or after this table has a considerable amount of rows in it:
START TRANSACTION;
INSERT INTO page_views SELECT * FROM page_views_tmp;
DELETE FROM page_views_tmp;
COMMIT;
Can anyone tell me what is the meaning of KEY fk_pickup_method (pickup_method_id),
KEY fk_deliv_method (delivery_method_id) lines. As pickup_method and deliv_method are not the tables. So what is the use of these lines.
CREATE TABLE `test` (
`idTest` int(11) NOT NULL AUTO_INCREMENT,
`Name` mediumtext NOT NULL,
`email` varchar(45) NOT NULL,
`password` varchar(45) NOT NULL,
`firstname` varchar(45) NOT NULL,
`lastname` varchar(45) NOT NULL,
`phone` bigint(20) unsigned NOT NULL,
`address_street` varchar(128) NOT NULL,
`address_apt` varchar(45) DEFAULT NULL,
`address_city` varchar(128) NOT NULL,
`address_state` varchar(2) NOT NULL,
`address_zip` int(11) NOT NULL,
`fax` bigint(20) unsigned DEFAULT NULL,
`account_balance` float NOT NULL DEFAULT '0',
`delivery_radius` float DEFAULT NULL,
`pickup_method_id` int(11) NOT NULL DEFAULT '0',
`delivery_method_id` int(11) NOT NULL,
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`lat` float NOT NULL DEFAULT '0',
`lng` float NOT NULL DEFAULT '0',
`timezone` varchar(45) NOT NULL,
PRIMARY KEY (`idTest`),
UNIQUE KEY `phone_UNIQUE` (`phone`),
KEY `fk_pickup_method` (`pickup_method_id`),
KEY `fk_deliv_method` (`delivery_method_id`)
)
They're INDEXes on the columns in the ()'s. But the fields are not constrained to being UNIQUE.
Look for {INDEX|KEY} in this MySQL document link.
Line
KEY fk_pickup_method (pickup_method_id)
defines an index named fk_pickup_method on table column pickup_method_id.
When you run EXPLAIN, under possible_keys column you'll see the name of the index.
The usual practice is to call the key as the column it indexes. That's the default behaviour if you don't specify the key name.
These are indexes on the fields pickup_method_id and delivery_method_id.
How mysql uses indexes : http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html
The name fk_ points to the intention of the creator to create a foreign key. But this is not a foreign key, and won't care about referential integrity for you.
Foreign keys in mysql (innodb) : http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
My guess is that these were intended to be FOREIGN KEY constraints and reference other tables.
InnoDB engine creates an index (if there isn't one) when a FOREIGN KEY constraint is defined.
MyISAM engine ignores FOREIGN KEY constraints but it still creates the index. Example:
CREATE TABLE test
( test_id int NOT NULL AUTO_INCREMENT,
delivery_method_id int NOT NULL,
PRIMARY KEY (test_id),
FOREIGN KEY fk_deliv_method (delivery_method_id)
REFERENCES delivery_method(delivery_method_id)
) ENGINE=MyISAM
DEFAULT CHARSET=utf8 ;
And then:
SHOW CREATE TABLE test ;
CREATE TABLE `test` (
`test_id` int(11) NOT NULL AUTO_INCREMENT,
`delivery_method_id` int(11) NOT NULL,
PRIMARY KEY (`test_id`),
KEY `fk_deliv_method` (`delivery_method_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8