There are different ways to create constraint in mariadb. We can either create them when creating the tables or after that. For example, the json_valid function could be defined in 3 different ways:
1) CREATE TABLE t2 (
j JSON
CHECK (JSON_VALID(j))
);
2) after table creation: "Alter table t2 add check(json_valid(j))"
3) "alter table t2 add constraint something check(json_valid(j))"
Which one is preferable and why?
Thank you in advance.
Assuming there are no INSERTs before the ALTER, they are all equivalent.
Doing everything in the CREATE TABLE is probably a tiny bit faster.
Related
I am trying to create an index in MySQL whereas the query will first check what column is not null. After checking, it will create the index on the column that is not null. However, I am not successful in creating this and it says I have an error, can someone help me? please see my code below
create index IDX_KSE_NO_01 on tb_kse(ifnull(ss_no, id_no);
#lad2025 is correct that MySQL does not support function-based indexes (like PostgreSQL does), but MySQL 5.7 introduced a feature for virtual generated columns based on expressions, and then you can create an index on a virtual column.
ALTER TABLE tb_kse ADD COLUMN either_no VARCHAR(10) AS (IFNULL(ss_no, id_no));
CREATE INDEX IDX_KSE_NO_01 ON tb_kse(either_no);
MySQL does not support function-based index. You should create normal index:
create index IDX_KSE_NO_01 on tb_kse(ss_no);
create index IDX_KSE_NO_02 on tb_kse(id_no);
And rewrite your query (OR-Expansion):
SELECT *
FROM tb_kse WHERE ss_no = ?
UNION
SELECT *
FROM tb_kse
WHERE ss_no IS NULL AND id_no = ?;
DBFiddle Demo
Another way is to create generated column and create index on top of it:
CREATE TABLE tb_kse(id_no INT, ss_no INT,
gen_col INT GENERATED ALWAYS AS (ifnull(ss_no, id_no)) STORED);
create index IDX_KSE_NO_01 on tb_kse(gen_col);
SELECT *
FROM tb_kse
WHERE gen_col = ?;
DBFiddle Demo 2
I have MySQL database about 5GB size and about 200 tables in it. All tables have prefix which I'd like to remove and I found some ideas for that.
The problem is that this database has referential integrity checking by using CONSTRAINT...FOREIGN KEY.
How to remove prefix from tables, including change in constraints, without manual modification or removing constraints?
Unfortunately you have to drop and recreate the foreign keys according to the mysql documentation on rename table:
Foreign keys that point to the renamed table are not automatically
updated. In such cases, you must drop and re-create the foreign keys
in order for them to function properly.
Use the tables in information_schema (mostly TABLES and COLUMNS) to construct the code you need. Perhaps 3 scripts would be wise:
SELECT CONCAT('ALTER TABLE ', table_name, ' DROP FOREIGN KEY ' ... ) FROM ...
SELECT CONCAT('RENAME TABLE ', ...
SELECT CONCAT('ALTER TABLE ', table_name, ' ADD FOREIGN KEY ' ... ) FROM ...
Then manually copy and paste the 3 scripts into the mysql commandline tool.
As for removing the prefix, look at the string functions MID, LOCATE, SUBSTRING_INDEX, etc., to see what would be useful.
Is it possible to use the LIKE statement on ALTER TABLE similar to CREATE TABLE in MySQL?
Eg. 'CREATE TABLE db.tbl1 LIKE db.tbl2'
This clones a database table's structure. I want to alter an existing table with the same columns but to pick up the primary keys of another table.
I was thinking of something like 'ALTER TABLE db.tbl1 LIKE db.tbl2' but this throws back an error.
Any ideas?
Thanks
I required a similar thing and settled to use the following procedure:
ALTER TABLE tbl1 RENAME tbl1_old;
CREATE TABLE tbl1 LIKE tbl2;
INSERT INTO tbl1 SELECT * FROM tbl1_old;
DROP TABLE tbl1_old;
Altough this is not a single statement it should do the job. Only problem could be different index settings (UNIQUE, etc.) which cause errors when doing the "INSERT INTO" of the original table contents.
Everything ALTER TABLE can do is explained here.
As you can see importing indexes from another table is not mentioned. You could probably do that with some clever information_schema querying, but I don't think it would be worth the cost.
It seems you can't.
I have a table that has 170,002,225 rows with about 35 columns and two indexes. I want to add a column. The alter table command took about 10 hours. Neither the processor seemed busy during that time nor were there excessive IO waits. This is on a 4 way high performance box with tons of memory.
Is this the best I can do? Is there something I can look at to optimize the add column in tuning of the db?
I faced a very similar situation in the past and i improve the performance of the operation in this way :
Create a new table (using the structure of the current table) with the new column(s) included.
execute a INSERT INTO new_table (column1,..columnN) SELECT (column1,..columnN) FROM current_table;
rename the current table
rename the new table using the name of the current table.
ALTER TABLE in MySQL is actually going to create a new table with new schema, then re-INSERT all the data and delete the old table. You might save some time by creating the new table, loading the data and then renaming the table.
From "High Performance MySQL book" (the percona guys):
The usual trick for loading MyISAM table efficiently is to disable keys, load the data and renalbe the keys:
mysql> ALTER TABLE test.load_data DISABLE KEYS;
-- load data
mysql> ALTER TABLE test.load_data ENABLE KEYS;
Well, I would recommend using latest Percona MySQL builds plus since there is the following note in MySQL manual
In other cases, MySQL creates a
temporary table, even if the data
wouldn't strictly need to be copied.
For MyISAM tables, you can speed up
the index re-creation operation (which
is the slowest part of the alteration
process) by setting the
myisam_sort_buffer_size system
variable to a high value.
You can do ALTER TABLE DISABLE KEYS first, then add column and then ALTER TABLE ENABLE KEYS. I don't see anything can be done here.
BTW, can't you go MongoDB? It doesn't rebuild anything when you add column.
Maybe you can remove the index before alter the table because what is take most of the time to build is the index?
Combining some of the comments on the other answers, this was the solution that worked for me (MySQL 5.6):
create table mytablenew like mytable;
alter table mytablenew add column col4a varchar(12) not null after col4;
alter table mytablenew drop index index1, drop index index2,...drop index indexN;
insert into mytablenew (col1,col2,...colN) select col1,col2,...colN from mytable;
alter table mytablenew add index index1 (col1), add index index2 (col2),...add index indexN (colN);
rename table mytable to mytableold, mytablenew to mytable
On a 75M row table, dropping the indexes before the insert caused the query to complete in 24 minutes rather than 43 minutes.
Other answers/comments have insert into mytablenew (col1) select (col1) from mytable, but this results in ERROR 1241 (21000): Operand should contain 1 column(s) if you have the parenthesis in the select query.
Other answers/comments have insert into mytablenew select * from mytable;, but this results in ERROR 1136 (21S01): Column count doesn't match value count at row 1 if you've already added a column.
Is it possible to create a temporary (session only) table from a select statement without using a create table statement and specifying each column type? I know derived tables are capable of this, but those are super-temporary (statement-only) and I want to re-use.
It would save time if I did not have to write up a create table command and keep the column list and type list matched up.
CREATE TEMPORARY TABLE IF NOT EXISTS table2 AS (SELECT * FROM table1)
From the manual found at http://dev.mysql.com/doc/refman/5.7/en/create-table.html
You can use the TEMPORARY keyword when creating a table. A TEMPORARY table is visible only to the current session, and is dropped automatically when the session is closed. This means that two different sessions can use the same temporary table name without conflicting with each other or with an existing non-TEMPORARY table of the same name. (The existing table is hidden until the temporary table is dropped.) To create temporary tables, you must have the CREATE TEMPORARY TABLES privilege.
In addition to psparrow's answer if you need to add an index to your temporary table do:
CREATE TEMPORARY TABLE IF NOT EXISTS
temp_table ( INDEX(col_2) )
ENGINE=MyISAM
AS (
SELECT col_1, coll_2, coll_3
FROM mytable
)
It also works with PRIMARY KEY
Use this syntax:
CREATE TEMPORARY TABLE t1 (select * from t2);
Engine must be before select:
CREATE TEMPORARY TABLE temp1 ENGINE=MEMORY
as (select * from table1)
ENGINE=MEMORY is not supported when table contains BLOB/TEXT columns
As I understand it, a SELECT statement will work on the temporary table if you're using it in something like phpMyAdmin, but following that SELECT, the temporary table will be gone. This means set up exactly what you want to do with it first, and don't view any results till your 'action' statements that change the data (DELETE, UPDATE) are complete.