I would like to rename an index. I've looked at the alter table documentation, but I can't figure out the syntax to simply rename an index. When doing it through the MySQL GUI, it drops the index, and creates a new one. While this works, I would like to avoid rebuilding the entire index just to change the name of an index.
[ADDITIONAL INFO]
In the alter table documentation it states
Alterations that modify only table
metadata and not table data can be
made immediately by altering the
table's .frm file and not touching
table contents. The following changes
are fast alterations that can be made
this way:
* Renaming a column or index.
However, when I tried to rename the index by editing the .frm file (on a test database) and restarting the server, it now states "Could not fetch columns" in the UI when trying to list the columns, and when trying to run a query, it returns the error "Unknown table engine ''". The .frm file has a lot of binary content. Is there a good tool for editing the binary info.
I answered this question in 2009. At that time there was no syntax in MySQL to rename an index.
Since then, MySQL 5.7 introduced an ALTER TABLE RENAME INDEX syntax.
http://dev.mysql.com/doc/refman/5.7/en/alter-table.html says in part:
RENAME INDEX old_index_name TO new_index_name renames an index. This is a MySQL extension to standard SQL. The content of the table remains unchanged. old_index_name must be the name of an existing index in the table that is not dropped by the same ALTER TABLE statement. new_index_name is the new index name, which cannot duplicate the name of an index in the resulting table after changes have been applied. Neither index name can be PRIMARY.
Earlier versions of MySQL, e.g. 5.6 and earlier, support no syntax in ALTER TABLE to rename an index (or key, which is a synonym).
The only solution was to ALTER TABLE DROP KEY oldkeyname, ADD KEY newkeyname (...).
There is no ALTER INDEX command in MySQL. You can only DROP INDEX and then CREATE INDEX with the new name.
Regarding your update above: perhaps the documentation isn't precise enough. Regardless, there's no SQL syntax to rename an index.
An index is a data structure that can be rebuilt from the data (in fact it's recommended to rebuild indexes periodically with OPTIMIZE TABLE). It takes some time, but it's a commonplace operation. Indexes data structures are separate from table data, so adding or dropping an index shouldn't need to touch the table data, as the documentation says.
Regarding the .frm file, MySQL does not support editing the .frm file. I wouldn't do it for any reason. You are 100% guaranteed to corrupt your table and make it unusable.
For MySQL 5.7:
ALTER TABLE tbl_name RENAME INDEX old_index_name TO new_index_name
For MySQL older versions:
ALTER TABLE tbl_name DROP INDEX old_index_name, ADD INDEX new_index_name (...)
See http://dev.mysql.com/doc/refman/5.7/en/alter-table.html
This question was asked ages ago, and was last updated over half a year ago.
Still I feel the need to add this tip:
If the indexed column is used elsewhere as a foreign key, you may encounter an error related to that. Doing this may help:
SET FOREIGN_KEY_CHECKS = 0;
ALTER TABLE tbl DROP INDEX index_name;
ALTER TABLE tbl ADD INDEX new_index_name (indexed_column);
SET FOREIGN_KEY_CHECKS = 1;
Hope someone finds this useful.
Related
I have an existing table in Sqlite. How do I add a unique constraint to it?
You can't add a constraint to existing table in SQLite,(In SQL there is a option for do that). You need to re-create the table with necessary contraints.
There is only a few option available for alter table command in sqlite. Please check the image:
Also check Sqlite org reference.
EDIT
However you can add unique index for your table to achieve the same effect.
So you can use the following query to achieve that:
CREATE UNIQUE INDEX your_unique_index ON your_table(column_name);
In most cases, UNIQUE and PRIMARY KEY constraints are implemented by
creating a unique index in the database.
Reference : SQLite Constraints
You can add constraint by creating unique index:
CREATE UNIQUE INDEX ux_friend_name ON friend(name);
where ux_friend_name is unique index name, friend(name) - table and its columns that will be affected by this constraint.
You can read more here.
I am assuming you are using SQLiteManager from FireFox, please create the table again, normally it doesn't allow to change the constraints when you have already created a table.
NOTE - It can be done using code too, this is another way of doing it..
Edited
See the image below
The database that I am tasked with fixing has a table with an identity column/PK that has a datatype of BigInt. This causes problem with the Access front end in that a datasheet to this linked table will not allow edits to the records. (This is a known issue with ODBC drivers and Access)
The table's Id column should never have been created as a bigint in the first place but that is a moot point now. I need to convert or recreate this column with a datatype of int, without losing the existing data.
There are ~2 million records in this table.
There are an unknown number of apps and Access apps that access this table so I am trying to do this as smoothly/stealthily as possible since the likelihood of finding all of those apps and modifying them before I make the change is slim.
Any thoughts or ideas?
I'm assuming the IDENTITY column is your PRIMARY KEY, and it's probably clustered :) MY advice below is based on those assumptions.
If you've only got a few indexes on the table, and the PRIMARY KEY is only referenced by a few FOREIGN keys, you should be able to change the datatype by:
Dropping any nonclustered indexes which contain the IDENTITY value.
Dropping the FOREIGN KEY constraints which point to the PRIMARY KEY.
Drop the PRIMARY KEY
ALTER TABLE tablename ALTER COLUMN columnname INT;
REcreate the PRIMARY KEY
Re-enable the FOREIGN KEY constraints with CHECK.
Recreate your nonclustered indexes.
As RBarryYoung pointed out, a lot of this can be scripted out by the SSMS GUI (if it's configured to allow saving changes), but the difference is that the GUI will create a temporary table, move your data, rename the new table to the old name, and drop the original.
Here's how to do it from Management Studio(SSMS):
First, make a backup copy of your database. If you make a mistake, or something unexpected happens, the easiest way to fix it is to restore from backup.
In the SSMS Explorer Pane, navigate to the table, then right-click on it and click "Design".
Select the Identity column's row and change it's datatype to "INT".
Save your changes, ignore the warning.
If you need a script instead, then replace step (4) above with:
Click the Script Changes button. Ignore the warning and then copy the script into you paste buffer. Make a new query window and paste the script into it. Then close the design window, cancelling any changes.
As Stuart Ainsworth points out, in later versions of SQL Server, it may prevent you from doing this, with a warning about "Dropping a Table". To fix this in SSMS, click the Tools..Options menu entry, then go to the "Tables and Designers" pane under "Designers" and uncheck the "Prevent saving changes that require table recreation" option.
I have to change my column data type and it is indexed. Altering the column giving me error that I need to drop the index, disabling won't work.
The question is how am I going to drop and recreate the exact index automatically? I can drop them but I have got no idea how I will be recreating them.
Cheers
What DBMS are you using? Some DB Management Systems have the ability to script their database objects, but the commands differ between them.
If you can create a script, you'd do so, drop the index, change the field's datatype, save, then run the script to re-create the index.
If you can't create a script for your index with your particular DBMS, you'll have to write down all the relevant fields and settings by hand, then drop the index, change the field's datatype, save, then manually recreate the index from your notes.
One way to do this would be to create your new index field then do an update query like:
UPDATE yourTable
SET newIdx = oldIdx
Then once the new index is filled just set it as the index field and remove the old field.
In my project having 23 million records and around 6 fields has been indexed of that table.
Earlier I tested to add delta column for Thinking Sphinx search but it turns in holding the whole database lock for an hour. Afterwards when the file is added and I try to rebuild indexes this is the query that holds the database lock for around 4 hours:
"update user_messages set delta = false where delta = true"
Well for making the server up I created a new database from db dump and promote it as database so server can be turned live.
Now what I am looking is that adding delta column in my table with out table lock is it possible? And once the column delta is added then why is the above query executed when I run the index rebuild command and why does it block the server for so long?
PS.: I am on Heroku and using Postgres with ika db model.
Postgres 11 or later
Since Postgres 11, only volatile default values still require a table rewrite. The manual:
Adding a column with a volatile DEFAULT or changing the type of an existing column will require the entire table and its indexes to be rewritten.
Bold emphasis mine. false is immutable. So just add the column with DEFAULT false. Super fast, job done:
ALTER TABLE tbl ADD column delta boolean DEFAULT false;
Postgres 10 or older, or for volatile DEFAULT
Adding a new column without DEFAULT or DEFAULT NULL will not normally force a table rewrite and is very cheap. Only writing actual values to it creates new rows. But, quoting the manual:
Adding a column with a DEFAULT clause or changing the type of an
existing column will require the entire table and its indexes to be rewritten.
UPDATE in PostgreSQL writes a new version of the row. Your question does not provide all the information, but that probably means writing millions of new rows.
While doing the UPDATE in place, if a major portion of the table is affected and you are free to lock the table exclusively, remove all indexes before doing the mass UPDATE and recreate them afterwards. It's faster this way. Related advice in the manual.
If your data model and available disk space allow for it, CREATE a new table in the background and then, in one transaction: DROP the old table, and RENAME the new one. Related:
Best way to populate a new column in a large table?
While creating the new table in the background: Apply all changes to the same row at once. Repeated updates create new row versions and leave dead tuples behind.
If you cannot remove the original table because of constraints, another fast way is to build a temporary table, TRUNCATE the original one and mass INSERT the new rows - sorted, if that helps performance. All in one transaction. Something like this:
BEGIN
SET temp_buffers = 1000MB; -- or whatever you can spare temporarily
-- write-lock table here to prevent concurrent writes - if needed
LOCK TABLE tbl IN SHARE MODE;
CREATE TEMP TABLE tmp AS
SELECT *, false AS delta
FROM tbl; -- copy existing rows plus new value
-- ORDER BY ??? -- opportune moment to cluster rows
-- DROP all indexes here
TRUNCATE tbl; -- empty table - truncate is super fast
ALTER TABLE tbl ADD column delta boolean DEFAULT FALSE; -- NOT NULL?
INSERT INTO tbl
TABLE tmp; -- insert back surviving rows.
-- recreate all indexes here
COMMIT;
You could add another table with the one column, there won't be any such long locks. Of course there should be another column, a foreign key to the first column.
For the indexes, you could use "CREATE INDEX CONCURRENTLY", it doesn't use too heavy locks on this table http://www.postgresql.org/docs/9.1/static/sql-createindex.html.
If I rename SQLite Tables/Columns/Rows after indices have been created, will the old indices still be functional?
Thanks!
If you're using ALTER TABLE with RENAME TO to rename a table, then as described on this page (from the sqlite docs) the indices will still work:
The ALTER TABLE command in SQLite allows the user to rename a table [...] If the table being renamed has triggers or indices, then these remain attached to the table after it has been renamed.
But note there's no renaming of columns allowed. This is one of the SQL features not implemented by sqlite:
Only the RENAME TABLE and ADD COLUMN variants of the ALTER TABLE command are supported. Other kinds of ALTER TABLE operations such as DROP COLUMN, ALTER COLUMN, ADD CONSTRAINT, and so forth are omitted.
Rows don't have names (except in the sense of having a PK) so there's not really a way of renaming them.
I highly recommend using Rails ActiveRecord migrations to maintain your database. This can be done outside of Rails. So you app doesn't need to be a Rails app to use rake tasks
See here for an excellent blog on how to do this http://exposinggotchas.blogspot.com/2011/02/activerecord-migrations-without-rails.html
Yes, the old indices will still be functional.
Be aware, that sqlite doesn't care about the names for the indexes. Initially when an index is created usually they are named after the table and field, so when you rename the table, the indexes will still have the name of the old table in it. This can cause problems, when you for example:
dump the table
rename the old table:
sqlite3 "$DB" "PRAGMA busy_timeout=20000; ALTER TABLE '$TABLE' RENAME TO '$TABLE"_backup"'"
reimport the dumped table
This will cause an error, that the indexes already exist.
Solution: Rename the indexes too, or delete them in the renamed table before you reimport the original (see this answer).