Mysql
 sql >> база данни >  >> RDS >> Mysql

Изберете стойности, които отговарят на различни условия на различни редове?

Добре, бях отрицателен за това, така че реших да го тествам:

CREATE TABLE userrole (
  userid INT,
  roleid INT,
  PRIMARY KEY (userid, roleid)
);

CREATE INDEX ON userrole (roleid);

Изпълнете това:

<?php
ini_set('max_execution_time', 120); // takes over a minute to insert 500k+ records 

$start = microtime(true);

echo "<pre>\n";
mysql_connect('localhost', 'scratch', 'scratch');
if (mysql_error()) {
    echo "Connect error: " . mysql_error() . "\n";
}
mysql_select_db('scratch');
if (mysql_error()) {
    echo "Selct DB error: " . mysql_error() . "\n";
}

$users = 200000;
$count = 0;
for ($i=1; $i<=$users; $i++) {
    $roles = rand(1, 4);
    $available = range(1, 5);
    for ($j=0; $j<$roles; $j++) {
        $extract = array_splice($available, rand(0, sizeof($available)-1), 1);
        $id = $extract[0];
        query("INSERT INTO userrole (userid, roleid) VALUES ($i, $id)");
        $count++;
    }
}

$stop = microtime(true);
$duration = $stop - $start;
$insert = $duration / $count;

echo "$count users added.\n";
echo "Program ran for $duration seconds.\n";
echo "Insert time $insert seconds.\n";
echo "</pre>\n";

function query($str) {
    mysql_query($str);
    if (mysql_error()) {
        echo "$str: " . mysql_error() . "\n";
    }
}
?>
\n";функционална заявка($str) { mysql_query($str); if (mysql_error()) { echo "$str:" . mysql_error() . "\н"; }}?>

Изход:

499872 users added.
Program ran for 56.5513510704 seconds.
Insert time 0.000113131663847 seconds.

Това добавя 500 000 произволни комбинации потребителски роли и има приблизително 25 000, които отговарят на избраните критерии.

Първа заявка:

SELECT userid
FROM userrole
WHERE roleid IN (1, 2, 3)
GROUP by userid
HAVING COUNT(1) = 3

Време за заявка:0,312 s

SELECT t1.userid
FROM userrole t1
JOIN userrole t2 ON t1.userid = t2.userid AND t2.roleid = 2
JOIN userrole t3 ON t2.userid = t3.userid AND t3.roleid = 3
AND t1.roleid = 1

Време на заявка:0,016 s

Това е вярно. Предложената от мен версия за присъединяване е двадесет пъти по-бърза от обобщената версия.

Съжалявам, но аз правя това, за да живея и работя в реалния свят, а в реалния свят тестваме SQL и резултатите говорят сами за себе си.

Причината за това трябва да е доста ясна. Обобщената заявка ще мащабира в цената с размера на таблицата. Всеки ред се обработва, обобщава и филтрира (или не) чрез HAVING клауза. Версията за присъединяване (с помощта на индекс) ще избере подмножество от потребители въз основа на дадена роля, след което ще провери това подмножество спрямо втората роля и накрая това подмножество срещу третата роля. Всяка селекциярелационна алгебра термини) работи върху все по-малко подмножество. От това можете да заключите:

Ефективността на версията за присъединяване става още по-добра с по-ниска честота на съвпадения.

Ако имаше само 500 потребители (от извадката от 500 000 по-горе), които имат трите посочени роли, версията за присъединяване ще стане значително по-бърза. Обобщената версия няма (и всяко подобрение на производителността е резултат от транспортирането на 500 потребители вместо 25k, което очевидно също получава версията за присъединяване).

Бях любопитен да видя как една истинска база данни (т.е. Oracle) ще се справи с това. Така че по същество повторих същото упражнение на Oracle XE (работи на същата настолна машина с Windows XP като MySQL от предишния пример) и резултатите са почти идентични.

Изглежда, че присъединяванията не се харесват, но както демонстрирах, обобщените заявки могат да бъдат с порядък по-бавни.

Актуализация: След известно обширно тестване , картината е по-сложна и отговорът ще зависи от вашите данни, вашата база данни и други фактори. Моралът на историята е тест, тест, тест.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. JDBC връща изключение на MySQLSyntaxError с правилно изявление

  2. DONTs и DONTs за индекси

  3. MySQL подготвени изявления

  4. Изисква се за присъединяване на 2 маси с техните FK в 3-та маса

  5. Външен ключ с няколко колони в MySQL?