2013-05-07 3 views
0

У меня есть две таблицы в той же базе данных, Device и EventData; обе таблицы имеют столбцы accountID и deviceID, которые также являются первичными ключами.Запрос MySQL с подзапросом для замедления

В таблице Device есть столбец с именем linkDescription.

Мне нужно дублировать некоторые строки в таблице EventData, чья accountID и deviceID, в Device таблицы, имея некоторый текст в колонке linkDescription.

Пример:

стол Устройство

accountID DeviceID linkDescription 
12345  5800  444 
12345  5700  445 
12345  5500  null <--literally null 
12388  4400  555 
12388  4450  555 

EventData стол

accountID DeviceID timestamp 
12345  5800  123335544 
12345  5700  123335544 
12345  5500  123335544 
12388  4400  123335544 
12388  4450  123335544 
12345  5800  123335548 
12345  5700  123335549 
12345  5500  123335549 
12388  4400  123335545 
12388  4450  123335546 

Теперь мне нужно дублировать некоторые строки на EventData и изменить accountID с помощью linkDescription из Device стол; так EventData теперь имеет следующие данные:

accountID DeviceID timestamp 
12345  5800  123335544 
12345  5700  123335544 
12345  5500  123335544 
12388  4400  123335544 
12388  4450  123335544 
12345  5800  123335548 
12345  5700  123335549 
12345  5500  123335549 
12388  4400  123335545 
12388  4450  123335546 
444   5800  123335544 <-duplicated data with new accountID from here 
445   5700  123335544 
555   4400  123335544 
555   4450  123335544 
444   5800  123335548 
445   5700  123335549 
555   4400  123335545 
555   4450  123335546 

Так что теперь я проверяю следующий запрос, который собирается быть частью более крупного INSERT INTO:

explain 
select * 
from EventData 
where 
    EventData.accountID in (
     select accountID 
     from Device 
     where Device.linkDescription > '0') 
    and EventData.deviceID in (
     select deviceID 
     from Device 
     where Device.linkDescription> '0') 
    and timestamp > (unix_timestamp(now()-interval 20 minute)); 

Но два медленно, и команду EXPLAIN показать это:

ID select_type   table  type   posible_keys key key_len ref  rows  Extra 
1 PRIMARY    EventData ALL    null   null null null 47555718 Using where 
3 DEPENDENT SUBQUERY Device  ALL    null   null null null 8043  Using where 
2 DEPENDENT SUBQUERY Device  index_subquery PRIMARY  PRIMARY 34 func  3  Using where 

Итак, насколько я понимаю, проверяет всю таблицу, и поэтому так медленно.

Как я могу сделать то, что хочу быстрее?

+4

Попробуйте использовать 'JOIN's. – Kermit

+0

'in' условия хорошо работают с детерминированными наборами (пример:' in (1, 2, 3, 5) ', но для подзапросов они могут быть катастрофическими, потому что подзапросы должны оцениваться один раз для каждой строки. для этого – Barranka

+0

У меня есть модуль JAVA, который записывается в таблицу EventData, поэтому я думаю, что я собираюсь написать код, чтобы делать то, что хочу. У меня есть программы VB.NET и вы делаете похожие вещи, как вы говорите, делая запросы отдельно и создание нового запроса со всеми внутри IN, поэтому никакого подзапроса не требуется. –

ответ

0

Я не уверен в вашем вопросе, что вы пытаетесь сделать, но вы должны использовать JOIN, чтобы ускорить процесс. Ваш SELECT может быть написано примерно так:

SELECT EventData.accountID from 
EventData 
RIGHT JOIN Device 
ON 
(
    (
     Device.accountID = EventData.accountID 
     OR Device.deviceID = Event.deviceID 
    ) 
    AND Device.linkDescription> '0' 
    AND timestamp > (unix_timestamp(now()-interval 20 minute)) 
); 

Вы, вероятно, может работать как INSERT будет работать оттуда.

+0

Я меняю OR на AND и возвращает много o нулей в одном столбце –

+0

Хм, можете ли вы упростить его, чтобы понять, что не так? выньте последние два 'AND' и посмотрите, получаете ли вы что-то. – woz

0

Рассмотрите возможность использования JOIN и вместо where условий:

select ed.* 
from 
    EventData as ed 
    inner join Device as d1 on ed.accountId = d1.accountId 
    inner join Device as d2 on ed.deviceId = d2.deviceId 
where 
    d1.linkDescription > '0' 
    and d2.linkDescription > '0' 
    and ed.timestamp > (unix_timestamp(now()-interval 20 minute)); 

Я дублируя Device таблицу просто исправить запрос.Если оба условие должно быть выполнено одновременно, а затем просто использовать Device таблицу один раз:

select ed.* 
from 
    EventData as ed 
    inner join Device as d on ed.accountId = d.accountId and ed.deviceId = d.deviceId 
where 
    d.linkDescription > '0' 
    and d.linkDescription > '0' 
    and ed.timestamp > (unix_timestamp(now()-interval 20 minute)); 

Надеется, что это помогает

+0

Сколько времени обычно занимает такие запросы, как те, которые содержатся в таблице MySQL с 47 миллионами строк? Причина большинства запросов, которые я использую в моих программах, занимает не больше пары секунд. ybe Я ожидаю слишком много от механизма базы данных. –

+0

@E_Blue Действительно, ваша таблица большая, но вам нужно учитывать, что условие 'in (select ...)' оценивается один раз ** для каждой строки ** в вашей таблице, так что это довольно штраф за производительность. Вот почему я рекомендую использовать объединения. Если ваши таблицы имеют соответствующие индексы, это должно ускорить работу до – Barranka

0

Его не обязательно ваш подзапросу, что происходит медленно, его основная таблица, которая составляет 47 миллионов строк:

и временная метка> (unix_timestamp (сейчас() - интервал 20 минут));

Добавить индекс на метку времени. Это должно решить. Я укажу, что подзапросы и объединения не имеют реальной разницы в производительности в современных версиях mysql. однако соединения более чистые и более понятные.

+0

. Я уже пробовал с временной отметкой и без нее, и команда EXPLAIN возвращает то же самое. –

Смежные вопросы