Sotomajor.org.ua - development, photography and a lot of stuff: Производительность DISTINCT vs array_unique()

На php.com.ua прочитал высказывание, что при выборке большого количества строк с уникальным значением одного столбца лучше использовать PHP для отбрасывания повторяющихся значений. Сделал тест. Результат под катом.

corner icon
2010.07.14 Замки під Львовом. Занедбані і не дуже Zacharovana Desna 2010 -> Local alcoholic gives us final instructions 2010.06.05 Винниченко Володимир - Між двох сил 2010.06.18 Lohika Company Day Lviv at night European trip 2010: Budapest European trip 2010: Brussels

Производительность DISTINCT vs array_unique()

2008-04-07 11:29 // // Section:

На php.com.ua прочитал высказывание, что при выборке большого количества строк с уникальным значением одного столбца лучше использовать PHP для отбрасывания повторяющихся значений.

Конечно же, я сразу знал что это не так и эксперимент это подтвердил.

Система:

ОС: Windows 2003 Server
PHP: 5.2.3
MySQL: 5.0.24

Результаты эксперимента:

results:
-----------------------
  MySQL DISTINCT query
-----------------------
Different names : 10902
Time: 6.1886458396912
-----------------------
      PHP
-----------------------
Different names : 10902
Time: 37.368453979492

Исходные данные:

В таблице было 1000000 строк, в поле name каждой из них - трехбуквенное значение сгенерированное случайным образом.


Таблица:
sql:
  1. CREATE TABLE `test` (
  2.   `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  3.   `name` varchar(45) NOT NULL,
  4.   PRIMARY KEY  (`id`)
  5. ) ENGINE=MyISAM DEFAULT CHARSET=latin1

Скрипт:
php:
  1. <?php
  2. echo "-----------------------\n";
  3. echo "  MySQL DISTINCT query\n";
  4. echo "-----------------------\n";
  5.  
  6. $time = microtime(TRUE);
  7.  
  8. $qr = mysql_query('SELECT DISTINCT `name` FROM `test`.`test`') or die(mysql_error());
  9. while ($aRow = mysql_fetch_assoc($qr))
  10.         $result[] = $aRow['name'];
  11. echo 'Different names : '.count($result)."\n";
  12. echo 'Time: '.(microtime(TRUE) - $time)."\n";
  13.  
  14. echo "-----------------------\n";
  15. echo "      PHP\n";
  16. echo "-----------------------\n";
  17.  
  18. unset($result);
  19. $time = microtime(TRUE);
  20. $qr = mysql_query('SELECT `name` FROM `test`.`test`') or die(mysql_error());
  21. while ($aRow = mysql_fetch_assoc($qr))
  22.         $result[] = $aRow['name'];
  23. $result = array_unique($result);
  24. echo 'Different names : '.count($result)."\n";
  25. echo 'Time: '.(microtime(TRUE) - $time)."\n";
  26. ?>

Построим индекс

Пойдем чуть дальше и построим индекс по столбцу `name`. Это должно дать неплохое уменьшение времени выполнения в случае DISTINCT. Справедливости ради нужно сказать, что само построение индекса для миллиона записей занимает достаточно много времени.

sql:
  1. ALTER TABLE `test`.`test` ADD INDEX `name_index`(`name`);

После этого выполняя тот самый скрипт - получаем результат:

result:
-----------------------
  MySQL DISTINCT query
-----------------------
Different names : 10902
Time: 0.42639398574829
-----------------------
      PHP
-----------------------
Different names : 10902
Time: 33.1578975632147

Выводы

В данной лабораторной работе мы лишний раз убедились в том, что язык SQL, который специально предназначен для работы с реляционными БД значительно выигрывает в производительности у языка PHP при выполнении вышеописанной задачи - получения выборки уникальных значений.

А добавление индекса оставляет PHP далеко позади в этом вопросе и заставляет его нервно курить в коридоре. :-)

  • — Author: vedeney · 2008-02-15 11:11 · #

    как по мне, так тест не очень чесный :)
    выполнять array_unique после того как куча памяти и ресурсов процесора были загружены задачей SQL сервера :)
    Но соглашусь, что в любом случае SQL будет в разы быстрее чем array_unique а с индексом и подавно :)

  • — Author: Сотомайор · 2008-02-15 11:43 · #

    Не думаю, что это сильно повлияло.
    1. array_unique выполнялся после простого запроса SELECT, а не с DISTINCT;
    2. Памяти на системе вполне достаточно, да и PHP ведь ограничен в используемой памяти, он никогда не подгребает всю свободную;
    3. Запрос и array_unique() идут последовательно, поэтому процессор уже освободится к тому моменту от выполнения запроса;
    4. Сделал тест с задержкой 10 секунд перед array_unique() чтобы систему “попустило” и освободились ресурсы. Результат практически такой же. Без задержки даже на 0.1 секунды быстрее получилось.

  • — Author: dusoft · 2008-02-15 11:56 · #

    Я думаю що тест доволі чесний, бо треба було визначити скільки часу забере отримання результату одним методом і іншим. В реальній ситуації при використанні другого методу ми ж не беремо дані з повітря. Простіше порівнювались же не швидкості алгоритмів які використовує MySQL і того алгоритму який було використано в другому варіанті, а порівнювався час необхідний на досягнення результату, і в другому випадку ми не можемо знехтувати операцією отримання даних з БД.

Add a comment: