![]() |
Модераторы: skyboy, MoLeX, Aliance, ksnk |
![]() ![]() ![]() |
|
Sunvas |
|
|||
![]() Соль и сахар ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3388 Регистрация: 12.3.2006 Где: Тосно Репутация: 2 Всего: 89 |
Есть таблица в которой ~1000000 записей. В ПХП есть одномерный массив, содежащий ~1000 чисел. Как за минимальное количество запросов вытащить из таблицы все записи ИДы которых содержаться в массиве?
![]() ![]() Это сообщение отредактировал(а) mishaSL - 12.9.2007, 15:48 -------------------- Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их. |
|||
|
||||
GZep |
|
|||
![]() участник Винграда ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1528 Регистрация: 7.7.2006 Где: Москва Репутация: -1 Всего: 32 |
что-то типа такого... -------------------- ![]() ![]() |
|||
|
||||
Diesel Draft |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 876 Регистрация: 18.1.2005 Где: Lviv, Ukraine Репутация: нет Всего: 5 |
Пример ясен? |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: 11 Всего: 261 |
GZep, синтаксически неверно.
Вариант Diesel Draft, приемлим, рационален. |
|||
|
||||
sTa1kEr |
|
|||
9/10 программиста ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1553 Регистрация: 21.2.2007 Репутация: 9 Всего: 146 |
Конструкция"id IN (value1, value2, value2)" работает достаточно медленно, тем более с таким количеством элементов. По этому я бы предложил в данном случае использовать временную таблицу.
Имхо, это будет намного производительнее. Таблица создается в памяти на время коннекта к базе и эффективность INNER JOIN должна оправдать два лишних запроса. |
|||
|
||||
Diesel Draft |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 876 Регистрация: 18.1.2005 Где: Lviv, Ukraine Репутация: нет Всего: 5 |
А если одновременно 2 запита пойдут
![]() |
|||
|
||||
sTa1kEr |
|
|||
9/10 программиста ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1553 Регистрация: 21.2.2007 Репутация: 9 Всего: 146 |
CREATE TABLE Syntax
Другими словами, временная таблица создается для одного коннекта и видима только в пределах этого коннекта, по этому можно не опасатся конфликтов. |
|||
|
||||
Diesel Draft |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 876 Регистрация: 18.1.2005 Где: Lviv, Ukraine Репутация: нет Всего: 5 |
А я не увидел, думал ты обычную хочешь впихнуть.
Но все ровно подумай, операция записи в БД медленней работает чем выборка данных. Если ты считаешь что IN будет тормозить то можно через or делают, но это вовсе БД убьет вовсе ![]() |
|||
|
||||
sTa1kEr |
|
|||
9/10 программиста ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1553 Регистрация: 21.2.2007 Репутация: 9 Всего: 146 |
||||
|
||||
Diesel Draft |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 876 Регистрация: 18.1.2005 Где: Lviv, Ukraine Репутация: нет Всего: 5 |
Почему? Ну вот ты так сказал, а ты на что то опирается?
П.С. Кстати 1000000 записей в Мускуле? Это немного жестоко получается. наверно уже притормаживает Это сообщение отредактировал(а) Diesel Draft - 26.7.2007, 17:58 |
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: 11 Всего: 261 |
Столько шума из ничего... Ну создадите вы временную таблицу, а толку? Выборку-то все равно надо делать...
|
|||
|
||||
Diesel Draft |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 876 Регистрация: 18.1.2005 Где: Lviv, Ukraine Репутация: нет Всего: 5 |
А где это ты будешь юзать?
|
|||
|
||||
Mal Hack |
|
|||
![]() Мудрый... ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 9926 Регистрация: 15.2.2004 Репутация: 11 Всего: 261 |
Временную таблицу? Когда выборка будет многоступенчатой...
|
|||
|
||||
sTa1kEr |
|
||||||||||
9/10 программиста ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1553 Регистрация: 21.2.2007 Репутация: 9 Всего: 146 |
Где вы увидели шум? Я просто предложил альтернативный более сложный, но и более производительный вариант. Да и что плохого в нескольких решениях? Я же никому не навязываю свое решение. А кому-то может будет познавательно просто узнать про временные таблицы.
Смысл временной таблицы я изложил выше. Написал маленький тестик для сравнения производительности. PHP 5.2.2 MySQL 5.0.38 Тестовая таблица:
Наполнение таблицы:
Тестиование.
Результаты теста
Как видите, при условиях Sunvas (1ый тест) временные таблицы выигрывают по времени в 2 раза. Однако, при увеличении количества строк в 10 раз, время при использовании IN увеличивается в 15 раз!, а INNER JOIN выполняется за то-же самое время. |
||||||||||
|
|||||||||||
Diesel Draft |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 876 Регистрация: 18.1.2005 Где: Lviv, Ukraine Репутация: нет Всего: 5 |
sTa1kEr, ты герой
![]() Просто мы делам в 3 раза больше операций |
|||
|
||||
FractalizeR |
|
||||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 273 Регистрация: 27.12.2007 Где: Россия/Москва Репутация: 2 Всего: 4 |
Ну, и что, до сих пор никто не нашел ошибку sTa1kEr? Тогда позвольте мне....
Обратите внимание на вот эту строчку:
Откуда у нас взялась таблица table? Мы ее не создавали! У нас есть только tmp (временная) и test (исходная). В результате этот запрос всегда НЕ ВЫПОЛНЯЕТСЯ, что создает ИЛЛЮЗИЮ того, что эта сумасшедшая комбинация действительно быстрее, чем IN конструкция... Если исправить этот table на test, как и должно быть, результаты теста будут совсем другими:
Отсюда мораль: всегда проверяйте результат выполнения запроса. sTa1kEr использует не слишком хорошо написанный класс по работе с базой данных, который, почему-то не выбрасывает ни ошибки, не исключения при ошибке в синтаксисе запроса.... Мой вариант PHP файла, на котором проводился тест, с использованием стандартных функций MySQL:
Это сообщение отредактировал(а) FractalizeR - 15.1.2008, 13:57 -------------------- Чтобы поблагодарить или наоборот поругать участника форума лучше пользоваться значками "+" и "-", изменяющими репутацию. Они находятся слева от поста под именем пользователя. |
||||||
|
|||||||
Sunvas |
|
|||
![]() Соль и сахар ![]() ![]() ![]() ![]() Профиль Группа: Участник Сообщений: 3388 Регистрация: 12.3.2006 Где: Тосно Репутация: 2 Всего: 89 |
Хм, видимо придется поднять старую темку.
-------------------- Воспитывая детей по своему образу и подобию, родители почему-то надеются, что они будут лучше их. |
|||
|
||||
SelenIT |
|
||||||
![]() баг форума ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3996 Регистрация: 17.10.2006 Где: Pale Blue Dot Репутация: 9 Всего: 401 |
Во-первых, FractalizeRу плюс за глазастость!
Но ситуация несколько сложнее. Я тестировал оба варианта (с mysqli и mysql_xxx) на двух машинах - стареньком Duron-1200 с 512 "мозгами" (одной планкой) и ноутбуке с Core2Duo T5500 (1.66 ГГц) и гигагабайтом памяти (двухканальной), оба под WinXP (к сожалению). Результаты вот: Duron-1200:
Core2Duo T5500:
Поражают как тормоза варианта с IN на старой одноядерной машине, так и быстрота варианта с джойном (без принудительного удаления времянки) на ней же. При хорошем запасе памяти и ресурсов проца, безусловно, вариант с IN (особенно при небольшом диапазоне) выглядит куда лучше, но вариант с времянкой, похоже, менее зависим от этих "мелочей". Надо бы протестить в более реальных условиях - под *NIX, под нагрузкой... Добавлено через 5 минут и 34 секунды
Это не класс, это улучшенное (по сравнению со старой php_mysql) расширение PHP5. Поддерживаются несколько запросов за вызов и новые возможности самой базы, но "волшебства" для перехвата ошибок в нем, увы, нет. -------------------- Осторожно! Данный юзер и его посты содержат ДГМО! Противопоказано лицам с предрасположенностью к зонеризму! |
||||||
|
|||||||
FractalizeR |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 273 Регистрация: 27.12.2007 Где: Россия/Москва Репутация: 2 Всего: 4 |
Меня вообще-то поражает не это.
Тестирование 1.000 тысячи записей с IN заняло 11.9 секунд, а тот же самый тест с IN но для 10.000 (в 10 раз больше) записей занял 1.6 секунды (в 10 раз меньше). Вам это не кажется странным? В общем, я думаю, вы просто что-то сделали неправильно. IN со скалярными значениями всегда быстрее любых других вариантов должен быть. Это сообщение отредактировал(а) FractalizeR - 16.1.2008, 00:47 -------------------- Чтобы поблагодарить или наоборот поругать участника форума лучше пользоваться значками "+" и "-", изменяющими репутацию. Они находятся слева от поста под именем пользователя. |
|||
|
||||
SelenIT |
|
|||
![]() баг форума ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3996 Регистрация: 17.10.2006 Где: Pale Blue Dot Репутация: 9 Всего: 401 |
Не в 10, а в 7, если быть совсем точным ![]()
Не могу за это поручиться, когда речь идет о MySQL - у нее, насколько я помню, "наследственные проблемы" с оптимизацией множественных OR в условии WHERE (а IN, насколько я понимаю - частный случай этого по сути). В каких-то версиях доходило до того, что UNION отдельных запросов с единственным значением в каждом оказывался быстрее. Нужно будет протестить как следует - чисто базу, без PHP, посмотреть EXPLAIN, желательно под никсами... постараюсь сделать ближе к вечеру, если кто сделает раньше/параллельно - буду только рад. -------------------- Осторожно! Данный юзер и его посты содержат ДГМО! Противопоказано лицам с предрасположенностью к зонеризму! |
|||
|
||||
FractalizeR |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 273 Регистрация: 27.12.2007 Где: Россия/Москва Репутация: 2 Всего: 4 |
Не в 10 раз меньше, а в 10 раз больше. Посмотрите внимательно на результаты теста. Тысяча строк отобрана за двенадчать секунд, а десять тысяч - за две секунды!
Почитайте мануал MySQL по использованию конструкции IN и вам все станет понятно. -------------------- Чтобы поблагодарить или наоборот поругать участника форума лучше пользоваться значками "+" и "-", изменяющими репутацию. Они находятся слева от поста под именем пользователя. |
||||
|
|||||
SelenIT |
|
||||
![]() баг форума ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3996 Регистрация: 17.10.2006 Где: Pale Blue Dot Репутация: 9 Всего: 401 |
Но 10 тыс. отобраны из одного миллиона, а 1 тыс. - из десяти миллионов! Посмотрите внимательно на условия теста ;). Есть же разница для сервера, имхо...
Вот относительно недавний FAQ, первый же вопрос которого полностью совпадает с тем, что некогда крепко засело в моем мозгу (причем автор утверждает, что и ORы, и IN с константами используют бинарный поиск - судя по комментам здесь, начиная с 4-й версии). Но ведь все равно, насколько я понимаю, этот бинарный поиск будет делаться для каждой строки исходной таблицы... Насчет UNOIN'а, признаю, прогнал (судя по тем же комментам). -------------------- Осторожно! Данный юзер и его посты содержат ДГМО! Противопоказано лицам с предрасположенностью к зонеризму! |
||||
|
|||||
FractalizeR |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 273 Регистрация: 27.12.2007 Где: Россия/Москва Репутация: 2 Всего: 4 |
Количество строк в таблице никто не менял. Откуда там один миллион и десять миллионов? Просто опять же автор теста допустил ошибку и тут. А я ее за ним скопировал. Нолик не дописан.
О том, как работает IN написано в мануале по MySQL. О ветке 3.x MySQL давно уже пора забыть. Это сообщение отредактировал(а) FractalizeR - 16.1.2008, 19:07 -------------------- Чтобы поблагодарить или наоборот поругать участника форума лучше пользоваться значками "+" и "-", изменяющими репутацию. Они находятся слева от поста под именем пользователя. |
||||
|
|||||
SelenIT |
|
|||
![]() баг форума ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3996 Регистрация: 17.10.2006 Где: Pale Blue Dot Репутация: 9 Всего: 401 |
Имхо, логично - индексу приходится шерстить в десять раз меньший диапазон, нагрузка на базу меньше... Читал. Сортирует, потом бинарный поиск. Написано, что это very quick, если в списке одни константы одного типа. Но вряд ли при этом предполагаются десятитысячные диапазонища... Пора, не спорю. Не всегда получается ;) -------------------- Осторожно! Данный юзер и его посты содержат ДГМО! Противопоказано лицам с предрасположенностью к зонеризму! |
|||
|
||||
sTa1kEr |
|
|||
9/10 программиста ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1553 Регистрация: 21.2.2007 Репутация: 9 Всего: 146 |
Извините, не имею тех тестов под рукой, надо будет поискать их. Но каюсь, что пред отправкой сообщения, я менял имена таблиц (и потом еще и редактировал пост с тем же намеренем), т.ч. сейчас уже не вспомню, толи это моя опечатка тут, толи в реальном тесте. Но
1. Количество строк действительно было разное, что я и написал в посте. 2. С корректными запросами я точно проводил тест. 3. Это было неоднократно замечено и испробовано на рабочих, реальных данных. Причем не только в MySQL но и в MSSQL, результат один - IN всегда проигрывает временной таблице, хранящейся в памяти(важно, что именно в памяти, т.к. можно и на диске создать временную). А на особо сложных запросах, это настолько особо критично. |
|||
|
||||
FractalizeR |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 273 Регистрация: 27.12.2007 Где: Россия/Москва Репутация: 2 Всего: 4 |
Хотелось бы, чтобы вы привели образцы скриптов, где IN медленнее, чтобы я смог провести тестирование на своем компьютере. Мне с трудом верится, что конструкция IN может быть настолько неоптимальной. Конечно, в MySQL 3.23 ее использование растягивалось в цепь OR и индекс не использовался. Но 3.23 пора забыть, как страшный сон
![]() Что касается количества рядов - то ведь оно касалось не таблицы, а функции, которая генерирует случайные id от нуля до переданного ей количества строк в таблице. Но сама таблица не менялась. Это сообщение отредактировал(а) FractalizeR - 16.1.2008, 20:30 -------------------- Чтобы поблагодарить или наоборот поругать участника форума лучше пользоваться значками "+" и "-", изменяющими репутацию. Они находятся слева от поста под именем пользователя. |
|||
|
||||
SelenIT |
|
|||
![]() баг форума ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3996 Регистрация: 17.10.2006 Где: Pale Blue Dot Репутация: 9 Всего: 401 |
FractalizeR, попробуйте Ваш же скрипт на таблице с еще на порядок большим (100 млн.) числом записей. Свои результаты запощу позже - "для чистоты эксперимента".
-------------------- Осторожно! Данный юзер и его посты содержат ДГМО! Противопоказано лицам с предрасположенностью к зонеризму! |
|||
|
||||
![]() ![]() ![]() |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | PHP: Базы Данных | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |