Периодически запрос перегружает MySql. Может кто сталкивался?

Главные вкладки

Аватар пользователя viko viko 8 января 2008 в 0:54

Примерно раз в месяц от провайдера приходят жалобы на запрос:
-------
SELECT t.word AS realword, i.word FROM search_total t LEFT JOIN search_index
i ON t.word = i.word WHERE i.word IS NULL;
-------
Время исполнения, секунд - 12
Кол-во просмотренных строк - 60048

Если вы хотите продолжать пользоваться услугами в текущем
режиме, просим вас максимально оперативно подтвердить решение
о смене тарифного плана на план, предусматривающий эксклюзивную
работу вашей БД.

А так то тарифный план устраивает пока.
Делаю оптимизацию таблиц и пишу им, мол вроде разобрались и т.п.
И вот уже третий раз...

Может кто сталкивался с проблемой?

Комментарии

Аватар пользователя VladSavitsky VladSavitsky 8 января 2008 в 1:12

А вы откройте phpmyadmin, выберите нужную базу и выполните этот запрос.
А лучше используйте ANALIZE, чтобы понять как именно исполняется запрос. Возможно он обрабатывает очень много данных (типа вечный цикл)...

Аватар пользователя PVasili PVasili 8 января 2008 в 2:35

запрос странный... из 2 таблиц по связанным полям у одной из таблиц оно = NULL
всего 60 000 просмотренных записей, у меня в одной таблице >1 000 000 и ни кто не ругается. подозреваю, что мастерхост Smile

Аватар пользователя Руслан Балькин Руслан Балькин (не проверено) 8 января 2008 в 14:12

Вообще надо смотреть SHOW CREATE TABLE для каждой таблицы и делать EXPLAIN SELECT ... для каждого такого запроса. У меня стоит 5.5 друпал, пока что экспериментирую... Вы уверены, что этот запрос ВООБЩЕ нужен?

У меня таблицы создаются так:
CREATE TABLE `search_index` (
`word` varchar(50) NOT NULL default '',
CREATE TABLE `search_total` (
`word` varchar(50) NOT NULL default '',

Соответственно условие не может быть выполнено:
WHERE i.word IS NULL;

Я бы сказал - поэкспериментировать с phpmyadmin - посмотреть, что этот запрос вообще выдает. Далее - попробовать модифицировать код - например WHERE вместо JOIN, либо использование временных таблиц.
Если запрос всегда пустой (как у меня) - может вообще от него избавиться?
удачи

Аватар пользователя viko viko 9 января 2008 в 15:33

Спасибо, что откликнулись.
Изучал дальше вопрос:
Запрос вызывает стандартный модуль search.module (Drupal 5.2) Текст функции приведен ниже. Смысл запроса в том, что он сравнивает таблицы search_index(40599 строк) и search_total(19449 строк) по полю word, и дальше функция удаляет из таблицы search_total строки по которым нет совпадений в таблице search_index.

Вот функция из search.module вызывающая запрос:
function search_update_totals() {
// Update word IDF (Inverse Document Frequency) counts for new/changed words
foreach (search_dirty() as $word => $dummy) {
// Get total count
$total = db_result(db_query("SELECT SUM(score) FROM {search_index} WHERE word = '%s'", $word));
// Apply Zipf's law to equalize the probability distribution
$total = log10(1 + 1/(max(1, $total)));
db_query("UPDATE {search_total} SET count = %f WHERE word = '%s'", $total, $word);
if (!db_affected_rows()) {
db_query("INSERT INTO {search_total} (word, count) VALUES ('%s', %f)", $word, $total);
}
}
// Find words that were deleted from search_index, but are still in
// search_total. We use a LEFT JOIN between the two tables and keep only the
// rows which fail to join.
$result = db_query("SELECT t.word AS realword, i.word FROM {search_total} t LEFT JOIN {search_index} i ON t.word = i.word WHERE i.word IS NULL");
while ($word = db_fetch_object($result)) {
db_query("DELETE FROM {search_total} WHERE word = '%s'", $word->realword);
}
}

Вроде запрос полезный и ничего в нем страшного быть не должно.

Как считаете его можно оптимизировать?

Вот что выдает EXPLAIN SELECT:

Для для наглядности сделал макет запроса в Access:

Аватар пользователя Руслан Балькин Руслан Балькин 9 января 2008 в 20:08

Все, понял уже :-(, что LEFT JOIN. Тогда весьма вероятно, что лучше и не получится Sad
Можно попробовать SELECT * FROM (SELECT t.word AS realword, i.word FROM search_total t LEFT JOIN search_index i ON t.word = i.word) tt WHERE word IS NULL;
Но по логике оригинальный запрос будет быстрее...