Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MySQL > Можно ли 3 запроса выполнить за 1 раз?


Автор: Coder 2.6.2008, 07:40
Есть 2 таблицы: 
№1 - основная - содержит все пришедшие пакеты;
№2 - вспомогательная - содержит только самый свежий пакет от каждого пользователя. 

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

Сейчас запись нового пакета в БД осуществляется через 4 запроса:
1. Проверить, чтобы пришедшее время в пакете было больше чем время в таблице №2 от этого пользователя.
2. Если пакет свежее, из таблицы №2 удалить запись и вставить новую.
3. Записать пакет в таблицу №1.

Возможно ли объединить в одном запросе к БД действия пунктов 1 и 2? И как, если возможно?

Автор: FINANSIST 2.6.2008, 08:11
 smile 
1)Блин, ну ты даёшь - на фига такой геморой с таблицами. Такое решение задачи неприемлемо с точки зрения проектирования БД. Храни всё в одном пакете , ты вложенными запросами можешь сформировать любой селект с любыми  критериями отбора, и не париться делая из 1 таблицы 2 .
2) Можешь за раз делать хоть сто запросов нажатием 1 кнопки на форме, только делай это програмно, через VBA 
Код


DoCMD.RunSQL("select.......................................;")
DoCMD.RunSQLRunSQL("select.......................................;")
DoCMD.RunSQLRunSQL("select.......................................;")

Автор: Coder 2.6.2008, 08:24
А если в основной таблице уже более 2000000 записей и это число быстро растет? И программу пишу я на Си с использованием MySQL API. Мне приходится 4 раза обращаться к БД, а хотелось бы 2.

Автор: Coder 2.6.2008, 08:43
Приложение серверное, работать должно быстро.

Автор: FINANSIST 2.6.2008, 08:46
SORRY! Не посмотрел что тема -  MYSQL , все равно (ИМХО) решение деления одной таблицы на две ( с одинаковой структурой) только для ускорения выборки довольно странно. 
Вопрос изначально стоит именно в этом, а не в выполнении цепочки последовательных запросов.
Я иногда дублирую таблицы - но это операция необходима для формировния временных срезов с дополнительной вставкой туда вычислений начальных, конечных сальдо, маржинальных доходов и прочих прелестей, (с последующим формированием из этого массива куба и очищением этой второй таблицы )но это вызванная необходимость. А зачем применять это в данном случае, не особо понятно.

Автор: Coder 2.6.2008, 08:54
FINANSIST, смотри:
Пользователь запрашивает - "дай мне последнюю информацию от ТОГО пользователя".
Я, по коду пользователя, сообщение которого ищут, выдергиваю из таблицы №2 данные. Притом простейшим запросом - select * from table1 where (user_ud=3). Все! А табличка в которой миллионы записей лишний раз не перебирается, тем более что искать в ней самое свежее сообщение прийдется по полю ДатаВремя.

Автор: Feldmarschall 2.6.2008, 09:03
Цитата(Coder @  2.6.2008,  08:54 Найти цитируемый пост)
скать в ней самое свежее сообщение прийдется по полю ДатаВремя. 

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

Цитата(Coder @  2.6.2008,  07:40 Найти цитируемый пост)
Возможно ли объединить в одном запросе к БД действия пунктов 1 и 2?

А зачем?

Автор: FINANSIST 2.6.2008, 09:14

Если действительно в основной таблице "миллионы" записей и запрос последних , самых актуальных пакетов приходится делать очень часто, то реализованный подход кажется эффективным, однако если придется сделать иную выборку, то от сложных вложенных запросов тебе всё равно не уйти .

Цитата

SORRY! Не посмотрел что тема -  MYSQL 

Принципиально не говорю о том, чего не знаю или в чём не уверен ( очень полезная в жизни превычка). 
Придётся соблюсти её и в даннос случае.

Будут вопросы по ACCESS,EXCEL, VBA - обращайся! 

Автор: Coder 2.6.2008, 09:53
Feldmarschall, если поиск последних данных делать по сразу по таблице №1, то сначала выбираю все сообщения от нужного пользователя, а потом среди них ищу максимальную дату - так сейчас работает.
Индексы есть, но нужно еще быстрее.

Цитата(Feldmarschall @  2.6.2008,  17:03 Найти цитируемый пост)
А зачем?

Затем чтобы при написании кода в Си 1 раз сформировать буфер с текстом запроса к БД и передать его функции mysql_query() на выполнение.

Цитата(FINANSIST @  2.6.2008,  17:14 Найти цитируемый пост)
Будут вопросы по ACCESS,EXCEL, VBA - обращайся! 

Ок. Спасибо!

Добавлено @ 10:03
Вот Запросы и условия их выполнения, которые мне нужно запихнуть в 1 запрос к БД:

Код

if ( (select count(*) from last_data where('2008-06-01 20-11-05'>date_time and user_id=7)) <>0 ) then
    begin
        delete from last_data where (user_id=7);
        insert into last_data values(....);
    end;


Можно ли реализовать такую условную ветку на MySQL?

Автор: Feldmarschall 2.6.2008, 12:10
Цитата(Coder @  2.6.2008,  09:53 Найти цитируемый пост)
Индексы есть, но нужно еще быстрее.

Извини, я не очень понял это предложение. Нужно ещё быстрее, чем что?

Цитата(Coder @  2.6.2008,  09:53 Найти цитируемый пост)
Затем чтобы при написании кода в Си 1 раз сформировать буфер с текстом запроса

а зачем?

Цитата(Coder @  2.6.2008,  09:53 Найти цитируемый пост)
потом среди них ищу максимальную дату - так сейчас работает.

не пробовал сразу получить из БД нужную строку?

Автор: Coder 2.6.2008, 12:48
Feldmarschall, МНЕ ТАК НУЖНО. Что зачем, что не пробывал? Много, что пробывал, для своей задачи я выбрал такой путь решения. Я не понял зачем эта вся писанина? Грубо говоря, я спрашиваю, можно ли вот это: 
Код

if ( (select count(*) from last_data where('2008-06-01 20-11-05'>date_time and user_id=7)) <>0 ) then
        delete from last_data where (user_id=7);
insert into last_data values(....);

"запихать" в один запрос на языке SQL для СУБД mysql. 

Автор: Feldmarschall 2.6.2008, 12:53
Затем, что если ты сам не озаботился найти смысл в своих действиях, то подсказать тебе это. Я задал тебе просте вопросы, на которые несложно ответить. И отделить осмысленные действия от бессмысленных. 
Грубо говоря, так никто не делает. А если ты такой оригинальный, то не надо у других спрашивать, как сделать через нетрадиционное место. 

Цитата(Coder @  2.6.2008,  12:48 Найти цитируемый пост)
Много что пробовал

Молодец. Однако пробы должны подкрепляться минимальными теоретическими познаниями. В частности - умением работать с бд. Отсутствие которого ты наглядно демонстрируешь. В результате твой вопрос превращается в детский каприз. 

Автор: skyboy 2.6.2008, 12:54
Цитата(Coder @  2.6.2008,  11:48 Найти цитируемый пост)
Грубо говоря, я спрашиваю, можно ли вот это: if ( (select count(*) from last_data where('2008-06-01 20-11-05'>date_time and user_id=7)) <>0 ) then    begin        delete from last_data where (user_id=7);        insert into last_data values(....);    end; "запихать" в один запрос на языке SQL для СУБД mysql. 

нет. в один нельзя. а теперь, может, давай поищем другие пути?

Автор: Coder 2.6.2008, 13:51
Цитата(Feldmarschall @  2.6.2008,  20:53 Найти цитируемый пост)
Затем, что если ты сам не озаботился найти смысл в своих действиях, то подсказать тебе это.

Я не против подсказки и хорошего совета, но все же хотелось услышать ответ на вопрос.

skyboy, спасибо, теперь я знаю что так сделать нельзя.  И можно поискать другие пути решения.

В таблице следующие поля:
id, user_id, date_time, message, param1, param2, ..., paramN

Как вытащить последние данные для конкретного пользователя?


Feldmarschall, таблица проиндексирована по полям id, user_id, date_time.

Автор: Feldmarschall 2.6.2008, 13:54
другие искать надо не потому, что кривым нельзя, а потому что он - кривой. 
чем не устраивает запрос order by date_time desc limit 1?

Автор: Coder 2.6.2008, 14:03
Код

select * from _info where (user_id=2) order by date_time desc limit 1;

У меня в локальной копии БД 1`965`603 записей, такой запрос в среднем выполняется за 1 секунду. Рабочий комп - Pentium M 1.6, 1Gb.

Сервер конечно мощнее, но и данных там больше.

Автор: Akina 2.6.2008, 14:08
Цитата(Coder @  2.6.2008,  15:03 Найти цитируемый пост)
У меня в локальной копии БД 1`965`603 записей, такой запрос в среднем выполняется за 1 секунду

Это говорит об отсутствии индекса. Или об использовании неправильного индекса.
давай начнем с цитирования структуры таблицы, включая индексы, и explain-а вот этого распоследнего запроса.

Автор: Feldmarschall 2.6.2008, 14:12
возможно, может понадобиться составной индекс user_id, date_time

Если в консоли выполнить запрос EXPLAIN select * from _info where (user_id=2) order by date_time desc limit 1; - что выведет?

Автор: Coder 2.6.2008, 14:16
Akina
Код

CREATE TABLE _info (
    id    INT UNSIGNED NOT NULL AUTO_INCREMENT,
    user_id    INT UNSIGNED NOT NULL,
    date_time    DATETIME NOT NULL,
    param1    DOUBLE NOT NULL,
    param2    DOUBLE NOT NULL,
    param3    FLOAT NOT NULL,
    param4    INT    UNSIGNED NOT NULL,
    PRIMARY KEY (id),
    KEY (user_id),
    KEY (date_time)
) ENGINE=MyISAM DEFAULT CHARACTER SET 'cp1251'; 


Код

explain select * from _info where (user_id=1) order by date_time desc limit 1;

выдает:
Код

| id | select_type | table    | type | possible_keys | key    | key_len | ref   | rows   | Extra
|  1 | SIMPLE      | gps_info | ref  | user_id       | user_id| 4       | const | 177026 | Using where; Using filesort


Автор: Feldmarschall 2.6.2008, 22:36
попробуй сделать 
Код

create index u_date on _info (user_id,date_time);

оно уберет filesort и должно стать быстрее.

Автор: Coder 3.6.2008, 02:35
Feldmarschall, и правда! Теперь время выполнения такой выборки = 0.00. И колонка Extra показывает, что используется только where.

Мне только не понятно, почему не был создан индекс при создании базы данных? Я же явно указал -  KEY (date_time). Или тут дело именно в составном индексе?


Feldmarschall,  +1

Автор: skyboy 3.6.2008, 03:20
Цитата(Coder @  3.6.2008,  01:35 Найти цитируемый пост)
тут дело именно в составном индексе

два индекса использоваться не могут, а у тебя ведь условие по одному и сортировка по другому.
потому составной ключ решил проблему. 
а ещё, так как where выполняется до сортировки, то порядок следования полей в объявлении индекса должен быть именно таким.

Автор: Feldmarschall 3.6.2008, 10:10
Coder, насколько я себе это представляю.
индекс - это файл, который, грубо говоря, состоит из пар "значение поля - позиция в файле", отсортированный по значению поля. 
Поиск по отсортированному списку происходит на порядки быстрее.
В случае с одиночным индексом он используется, но помогает выбрать только строки одного юзера - а их 17 тысяч. А их уже приходится сортировать заново - ведь индекс по дате здесь не получится использовать - он тоже по всему файлу строится, и без информации о юзере.
А составной индекс отсортирован по двум полям, то есть, имеет вид
1, 2001
1, 2002
1, 2003
2, 2001
2, 2005
5, 2008

соответственно, поиск сводится нахождению сначала юзера, а потом - максимальной даты для него.

Автор: Coder 4.6.2008, 04:09
Feldmarschall, доходчиво.

Помечаю вопрос ка решенный.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)