I have a table named product. In this table, I want to update some product id values, however I cannot do it directly, my 'where' condition needs to determine records based on value from another table, so I do:
update product set prod_active = 0 where prod_id in (
select prod_id from user_prod_sel where seltype = 100
)
The problem I have here is this is very slow. How can I convert this into a oin based query that can give me faster results?
Any help is greatly appreciated.
You should be able to do this:
UPDATE product a
JOIN user_prod_sel b ON a.prod_id = b.prod_id AND b.selType = 100
SET a.prod_active = 0
If you want to speed up the query you need to add indexes for product.prod_id and user_prod_sel.seltype. Table indexes exist exactly for speeding up selection of data.
ALTER TABLE `product` ADD INDEX `prod_id` (`prod_id`)
Do not add index product.prod_id if it already has index (if it's a primary key, for example).
ALTER TABLE `user_prod_sel` ADD INDEX `seltype` (`seltype`)
And then:
UPDATE `product`, `user_prod_sel`
SET `product`.`prod_active` = 0
WHERE
`product`.`prod_id` = `user_prod_sel`.`prod_id` AND
`user_prod_sel`.`seltype` = 100
Of course, creating indexes is a task which is performed once, not before every UPDATE query.
Related
I use following query to fetch around data from 15 columns from four tables
SELECT company_table.some_values,
log_table.somevalues,
employee_table.somevalues,
manager_table.somevalues
FROM company_table
JOIN log_table
ON company_table.id = log_table.id
AND company_table.department = log_table.dept
JOIN employee_table
ON employee_table.id = log_table.id
AND employee_table.year = log_table.joining
AND employee_table.department = log_table.dept
JOIN manager_table
ON manager_table.id = log_table.id
AND manager_table.year = log_table.joining
AND manager_table.department = log_table.dept
ORDER BY log_table.id DESC
Output is correct but it takes more time to execute. But if I remove order by then execution time is reduced by considerable amount. I tried with order by ascending still it takes more time
I suspect your tables are not designed correctly.
I think you have recurring values in your log_table.id column, because I suspect it doesnt truly have a unique index for a primary key, or a correct primary key, since its id column doubles up as the company id also. This is why I have this notion:
ON company_table.id = log_table.id
AND company_table.department = log_table.dept
If either or both of these columns are/make up your primary key, which I suspect they are not, they are not the correct choice.
So it will do a good job of retrieving things in the order they are found, but a little extra work has to be done when ordering because you can potentially have colliding values, that and you have to join on 2 columns.
If what above is true, you can try this. Backup before trying, or try on dev.
Try adding a new column for a primary key and ordering on that:
ALTER TABLE log_table DROP PRIMARY KEY;
ALTER TABLE log_table ADD pk_column INT AUTO_INCREMENT PRIMARY KEY;
then ORDER BY pk_column DESC.
If you have specified another column in log_table as your primary key, order by on that instead.
I'm trying to write a query to update a FK column in table B using the primary key column in table A. If there are duplicate entries in table A, I'd like to use the max id of the duplicate entry to insert into table B.
I have the first part of the query written but I'm unsure about the duplicate entry part.
Here's what I have so far...
UPDATE calliope_media.videos v
JOIN calliope_media.video_ingress_queue viq ON v.provider_unique_id = viq.provider_unique_id
SET v.video_ingress_id = viq.id;
This is how your query should look.
UPDATE B
SET B.the_column_ID = (SELECT MAX(A.some_ID)
FROM A
WHERE A.matching_value = B.matching_value)
This is the overall structure. I haven't adapted to your specific requirements, since I don't fully understand them. But this should get you back on track.
I want to create a unique combokey on Site and ASIN and remove duplicates while creating
so far I have
ALTER TABLE Products ADD UNIQUE (Site,ASIN)
I figure there needs to be an "On Duplicate" but I cant find the right thing to do within http://dev.mysql.com/doc/refman/5.0/en/alter-table.html .. does anyone have a suggestion?
I don't think there is such a thing as ON DUPLICATE when adding a UNIQUE KEY. So you need to find a workaround. Here is a suggestion:
1- Identify the duplicate rows and store the values in a temp table.
CREATE TEMPORARY TABLE Duplicates
(SELECT
Site, ASIN
FROM
Products
GROUP BY
Site, ASIN
HAVING
COUNT(*) > 1
);
2- join the temp table with the original table and delete the duplicate rows that you don't need anymore. (from the comments I think you want to remove the ones with SKU IS NULL)
DELETE p
FROM
Products AS p
INNER JOIN
Duplicates AS d
ON
d.Site = p.Site and d.ASIN = p.ASIN
WHERE
p.SKU IS NULL;
3- create your unique key:
ALTER TABLE Products ADD UNIQUE KEY (Site, ASIN);
Here is a fiddle I created.
I'm running what I thought was a fairly straight forward update on a fairly large table. I am trying to find out why this simple update is running so slowly. It took about 5 hours to complete.
master table: approx 2m row and 90 fields.
builder table: approx 1.5m rows and 15 fields
I had initially attempted the insert directly:
-- Update master table with newly calculated mcap
update master as m
inner join
(select b.date_base, b.gvkey, sum(b.sec_cap) as sum_sec_mkt
from builder as b
group by b.gvkey, b.date_base) as x
on x.gvkey = m.gvkey AND
x.date_base = m.date_base
set m.mcap = x.sum_sec_mkt;
Unfortunately this ran for a number of hours and I finally killed it after waiting 4hrs.
I then thought I'd create a temporary table and insert the results from the initial select into it.
CREATE TABLE `temp_mkt_cap` (
`date_base` date NOT NULL,
`gvkey` varchar(15) DEFAULT NULL,
`mkt_cap` double DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- insert market cap values in to temporary table
insert into temp_mkt_cap
select b.date_base, b.gvkey, sum(b.sec_cap) as sum_sec_mkt
from builder as b
group by b.gvkey, b.date_base;
ALTER TABLE temp_mkt_cap
add primary key (date_base, gvkey);
The insert worked fine with temp_mkt_cap having about 1.4m rows, but the final update took 5hrs to complete.
-- Update master table with newly calculated mcap
update master as m
inner join temp_mkt_cap as mc
on m.date_base = mc.date_base AND m.gvkey = mc.gvkey
set m.mcap = mc.mkt_cap;
'master' has 'date_base' and gvkey_iid as PRIMARY KEYS and gvkey as a KEY.
I have completed more complicated inserts and updates on the table before and can't work out why this isn't working.
Any help would be greatly appreciated.
Thanks,
Update: The keys on the master table are:
ALTER TABLE master
ADD PRIMARY KEY (gvkey_iid,date_base),
ADD KEY date_offset (date_offset),
ADD KEY gvkey (gvkey),
ADD KEY iid (iid);
Update I added a new key to the master table and the update ran in 93.6secs, down from 5 hours. Thanks for everyone's help.
ALTER TABLE master
ADD KEY 'date-gvkey' (date_base, gvkey);
Since you are joining on mc.date_base AND m.gvkey = mc.gvkey, you need an index on these fields in the same order you are joining them, on both tables.
If you are joining table1 with table2 on table1.field1 = table2.field1 AND table1.field2 = table2.field2, you need an index on (table1.field1, table1.field2) AND (table2.field1, table2.field2).
Not null fields are preferable.
Also, because you are updating from the mc.mkt_cap field, you need a SINGLE key on this field if it is NOT already the first field of a composite key you created earlier.
ALL other keys or indexes are going to possibly slow down your query.
Please inspect carefully your database...
I am trying to update rows in a data table that intersect rows in a smaller index table. The two tables are joined on the composite PK of the data table, and explain-select using the same criteria shows that the index is being used properly, and the correct unique rows are fetched - but I'm still having issues with the update.
The update on the joined tables works fine when there's only 1 row in the temp table, but when I have more rows, I get MySql Error 1175, and none of the WHERE conditions I specify are recognized.
I'm aware that I can just switch off safe mode with SET SQL_SAFE_UPDATES=0, but can anyone tell me what I'm not understanding here? Why is my WHERE condition not accepted, and why does it even need a where when I'm doing a NATURAL JOIN - and why does this work with only one row in the right-hand-side table (MyTempTable)?
The Code
Below is vastly simplified, but structurally identical create table & updates representing my problem.
-- The Data Table.
Create Table MyDataTable
(
KeyPartOne int not null,
KeyPartTwo varchar(64) not null,
KeyPartThree int not null,
RelevantData varchar(200) null,
Primary key (KeyPartOne, KeyPartTwo, KeyPartThree)
) Engine=InnoDB;
-- The 'Temp' table.
Create Table MyTempTable
(
KeyPartOne int not null,
KeyPartTwo varchar(64) not null,
KeyPartThree int not null,
Primary key (KeyPartOne, KeyPartTwo, KeyPartThree)
)Engine=Memory;
-- The Update Query (works fine with only 1 row in Temp table)
update MyDataTable natural join MyTempTable
set RelevantData = 'Something Meaningful';
-- Specifying 'where' - roduces same effect as the other update query
update MyDataTable mdt join MyTempTable mtt
on mdt.KeyPartOne = mtt.KeyPartOne
and mdt.KeyPartTwo = mtt.KeyPartTwo
and mdt.KeyPartThree = mtt.KeyPartThree
set RelevantData = 'Something Meaningful'
where mdt.KeyPartOne = mtt.KeyPartOne
and mdt.KeyPartTwo = mtt.KeyPartTwo
and mdt.KeyPartThree = mtt.KeyPartThree;
P.S. Both of the above update statements work as expected when the temp table contains only one row, but give me the error when there's more than one row. I'm seriously curious about why!
In your first UPDATE query, you use NATURAL JOIN, which is the same as NATURAL LEFT JOIN.
In your second UPDATE query, you use JOIN, which is the same as INNER JOIN.
A LEFT JOIN is not the same as an INNER JOIN, and a NATURAL JOIN is not the same as a JOIN.
Not sure what you're trying to do, but if you are trying to update all rows in MyDataTable where a corresponding entry exists in MyTempTable, this query should do the trick:
UPDATE
myDataTable mdt
INNER JOIN MyTempTable mtt ON
mdt.KeyPartOne = mtt.KeyPartOne
AND mdt.KeyPartTwo = mtt.KeyPartTwo
AND mdt.KeyPartThree = mtt.KeyPartThree
SET
mdt.RelevantData = 'Something Meaningful'
If that's not what you're trying to do, please clarify and I will update my answer.
Per the MySql forum, the update queries are valid, and the fact that they don't work in Workbench with safe-update mode turned on does not indicate that there's anything wrong with the index. It's just a quirk of Workbench's "don't-shoot-yourself-in-the-foot" mode. :-)