30. テーブルスキャン
mysql56> EXPLAIN SELECT Name, Continent, Population
-> FROM Country
-> WHERE Continent = 'Asia'
-> ORDER BY Population LIMIT 5;
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
| 1 | SIMPLE | Country | ALL | NULL | NULL | NULL | NULL | 239 | Using where; Using filesort |
+----+-------------+---------+------+---------------+------+---------+------+------+-----------------------------+
1 row in set (0.00 sec)
* 1行ずつデータをフェッチして
* WHERE句のカラムで評価し
* ソートバッファに詰め込み
* クイックソートして
* 先頭から5件取り出す
31. テーブルスキャン
for (my $rownum= 0; $rownum < scalar(@$country_table); $rownum++)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
scan_where_scan_orderby.pl
32. テーブルスキャン
for (my $rownum= 0; $rownum < scalar(@$country_table); $rownum++)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
1行ずつフェッチして
scan_where_scan_orderby.pl
33. テーブルスキャン
for (my $rownum= 0; $rownum < scalar(@$country_table); $rownum++)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
WHERE句で評価
scan_where_scan_orderby.pl
34. テーブルスキャン
for (my $rownum= 0; $rownum < scalar(@$country_table); $rownum++)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
マッチしたら
ソートバッファに詰める
scan_where_scan_orderby.pl
35. テーブルスキャン
for (my $rownum= 0; $rownum < scalar(@$country_table); $rownum++)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
ソートバッファの中身を
クイックソート
scan_where_scan_orderby.pl
36. テーブルスキャン
for (my $rownum= 0; $rownum < scalar(@$country_table); $rownum++)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
先頭の5件を出力したら
そこでループを抜ける
scan_where_scan_orderby.pl
37. テーブルスキャン
$ ./scan_where_scan_orderby.pl
Maldives Asia 286000
Brunei Asia 328000
Macao Asia 473000
Qatar Asia 599000
Bahrain Asia 617000
Total rows evaluted are 239, sorted are 51.
scan_where_scan_orderby.pl
5行の出力に対して、
239回のWHERE評価と
51行のファイルソート
47. WHERE狙いのキー
mysql56> ALTER TABLE Country ADD KEY index_continent(continent);
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql56> EXPLAIN SELECT Name, Continent, Population
-> FROM Country
-> WHERE Continent = 'Asia'
-> ORDER BY Population LIMIT 5;
+----+-------------+---------+------+-----------------+-----------------+---------+-------+------
+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
|
+----+-------------+---------+------+-----------------+-----------------+---------+-------+------
+----------------------------------------------------+
| 1 | SIMPLE | Country | ref | index_continent | index_continent | 1 | const | 51 | Using index condition; Using
where; Using filesort |
+----+-------------+---------+------+-----------------+-----------------+---------+-------+------
+----------------------------------------------------+
1 row in set (0.00 sec)
* WHERE句のレンジをインデックスから取り出し
* ソートバッファに詰め込み
* クイックソートして
* 先頭から5件取り出す
48. WHERE狙いのキー
my $index_num = $country_index->{map}->{Asia};
my $rownum_array= $country_index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
indexed_where_scan_orderby.pl
49. WHERE狙いのキー
my $index_num = $country_index->{map}->{Asia};
my $rownum_array= $country_index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
WHERE句のレンジを
インデックスから取り出す
indexed_where_scan_orderby.pl
50. WHERE狙いのキー
my $index_num = $country_index->{map}->{Asia};
my $rownum_array= $country_index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
取り出した行を全部
ソートバッファに詰めて
indexed_where_scan_orderby.pl
51. WHERE狙いのキー
my $index_num = $country_index->{map}->{Asia};
my $rownum_array= $country_index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
クイックソートして
indexed_where_scan_orderby.pl
52. WHERE狙いのキー
my $index_num = $country_index->{map}->{Asia};
my $rownum_array= $country_index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$sorted++;
push(@{$sort_buffer->{$row->{population}}}, $rownum);
}
my $sorted_buffer= filesort_single_column($sort_buffer);
foreach my $rownum (@$sorted_buffer)
{
my $row= $country_table->[$rownum];
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last;}
}
先頭の5件を出力したら
ループを抜ける
indexed_where_scan_orderby.pl
53. WHERE狙いのキー
$ ./indexed_where_scan_orderby.pl
Maldives Asia 286000
Brunei Asia 328000
Macao Asia 473000
Qatar Asia 599000
Bahrain Asia 617000
Total rows evaluted are 1, sorted are 51.
WHEREの評価は1回で済むけど
indexed_where_scan_orderby.pl
51行をファイルソート
56. ORDER BY狙いのキー
mysql56> ALTER TABLE Country ADD KEY index_population(population);
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql56> EXPLAIN SELECT Name, Continent, Population
-> FROM Country
-> WHERE Continent = 'Asia'
-> ORDER BY Population LIMIT 5;
+----+-------------+---------+-------+---------------+------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+------------------+---------+------+------+-------------+
| 1 | SIMPLE | Country | index | NULL | index_population | 4 | NULL | 5 | Using where |
+----+-------------+---------+-------+---------------+------------------+---------+------+------+-------------+
1 row in set (0.00 sec)
* インデックスに沿って行を取り出し
* WHERE句にマッチするか判定して
* 5件データが揃ったらループから抜ける
57. ORDER BY狙いのキー
my $cardinality= scalar(keys(%{$index->{map}}));
LOOP: for (my $index_num= 0;
$index_num < $cardinality;
$index_num++)
{
my $rownum_array= $index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last LOOP;}
}
}
}
scan_where_indexed_orderby.pl
58. ORDER BY狙いのキー
my $cardinality= scalar(keys(%{$index->{map}}));
LOOP: for (my $index_num= 0;
$index_num < $cardinality;
$index_num++)
{
my $rownum_array= $index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last LOOP;}
}
}
}
インデックスに沿って
行を取り出して
scan_where_indexed_orderby.pl
59. ORDER BY狙いのキー
my $cardinality= scalar(keys(%{$index->{map}}));
LOOP: for (my $index_num= 0;
$index_num < $cardinality;
$index_num++)
{
my $rownum_array= $index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last LOOP;}
}
}
}
WHERE句にマッチするか
判定して
scan_where_indexed_orderby.pl
60. ORDER BY狙いのキー
my $cardinality= scalar(keys(%{$index->{map}}));
LOOP: for (my $index_num= 0;
$index_num < $cardinality;
$index_num++)
{
my $rownum_array= $index->{index}->[$index_num];
foreach my $rownum (@$rownum_array)
{
my $row= $country_table->[$rownum];
$evaluted++;
if ($row->{continent} eq "Asia")
{
printf("%st%st%dn",
$row->{name},
$row->{continent},
$row->{population});
if (++$count >= 5)
{last LOOP;}
}
}
}
先頭の5件を出力したら
そこでループを抜ける
scan_where_indexed_orderby.pl
61. ORDER BY狙いのキー
$ ./scan_where_indexed_orderby.pl
Maldives Asia 286000
Brunei Asia 328000
Macao Asia 473000
Qatar Asia 599000
Bahrain Asia 617000
Total rows evaluted are 79, sorted are 0.
ソートのオーバーヘッドはないものの、
scan_where_indexed_orderby.pl
79行をWHERE句評価
78. スキャンジョイン
mysql56> EXPLAIN SELECT Name, Language, Population, Percentage
-> FROM Country INNER JOIN CountryLanguage ON Country.Code= CountryLanguage.CountryCode
-> WHERE Country.continent = 'Asia'
-> ORDER BY Percentage LIMIT 5;
+----+-------------+-----------------+------+---------------+------+---------+------+------
+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra
|
+----+-------------+-----------------+------+---------------+------+---------+------+------
+----------------------------------------------------+
| 1 | SIMPLE | CountryLanguage | ALL | NULL | NULL | NULL | NULL | 984 | Using temporary; Using filesort
|
| 1 | SIMPLE | Country | ALL | NULL | NULL | NULL | NULL | 239 | Using where; Using join buffer
(Block Nested Loop) |
+----+-------------+-----------------+------+---------------+------+---------+------+------
+----------------------------------------------------+
2 rows in set (0.00 sec)
* 外側のテーブルから1行データをフェッチして
* WHEREとONのカラムで内側のテーブルを評価して
ソートバッファに詰め込み
* 外側のテーブルから次の1行をフェッチして…を繰り返し
* クイックソートして先頭から5件取り出す
79. スキャンジョイン
for (my $language_rownum= 0;
$language_rownum < scalar(@$language_table);
$language_rownum++)
{
my $language_row= $language_table->[$language_rownum];
for (my $country_rownum= 0;
$country_rownum < scalar(@$country_table);
$country_rownum++)
{
my $country_row= $country_table->[$country_rownum];
$evaluted++;
if ($language_row->{countrycode} eq $country_row->{code} &&
$country_row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$language_row->{percentage}}},
[$language_rownum, $country_rownum]);
}
}
}
ファイルソート以降は略
scan_join_scan_where_scan_orderby.pl
80. スキャンジョイン
for (my $language_rownum= 0;
$language_rownum < scalar(@$language_table);
$language_rownum++)
{
my $language_row= $language_table->[$language_rownum];
for (my $country_rownum= 0;
$country_rownum < scalar(@$country_table);
$country_rownum++)
{
my $country_row= $country_table->[$country_rownum];
$evaluted++;
if ($language_row->{countrycode} eq $country_row->{code} &&
$country_row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$language_row->{percentage}}},
[$language_rownum, $country_rownum]);
}
}
}
ファイルソート以降は略
外側のテーブルから
1行ずつフェッチ
scan_join_scan_where_scan_orderby.pl
81. スキャンジョイン
for (my $language_rownum= 0;
$language_rownum < scalar(@$language_table);
$language_rownum++)
{
my $language_row= $language_table->[$language_rownum];
for (my $country_rownum= 0;
$country_rownum < scalar(@$country_table);
$country_rownum++)
{
my $country_row= $country_table->[$country_rownum];
$evaluted++;
if ($language_row->{countrycode} eq $country_row->{code} &&
$country_row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$language_row->{percentage}}},
[$language_rownum, $country_rownum]);
}
}
}
ファイルソート以降は略
内側のテーブルでも
1行ずつフェッチして
scan_join_scan_where_scan_orderby.pl
82. スキャンジョイン
for (my $language_rownum= 0;
$language_rownum < scalar(@$language_table);
$language_rownum++)
{
my $language_row= $language_table->[$language_rownum];
for (my $country_rownum= 0;
$country_rownum < scalar(@$country_table);
$country_rownum++)
{
my $country_row= $country_table->[$country_rownum];
$evaluted++;
if ($language_row->{countrycode} eq $country_row->{code} &&
$country_row->{continent} eq "Asia")
{
$sorted++;
push(@{$sort_buffer->{$language_row->{percentage}}},
[$language_rownum, $country_rownum]);
}
}
}
ファイルソート以降は略
評価&ソートバッファ
scan_join_scan_where_scan_orderby.pl
83. スキャンジョイン
$ ./scan_join_scan_where_scan_orderby.pl
United Arab Emirates Hindi 2441000 0.000000
Bahrain English 617000 0.000000
Japan Ainu 126714000 0.000000
Kuwait English 1972000 0.000000
Lebanon French 3282000 0.000000
Total rows evaluted are 235176, sorted are 239.
評価する行の数が倍倍ゲェム
scan_join_scan_where_scan_orderby.pl
85. 直感の赴くまま
SELECT Name, Language, Population, Percentage
FROM Country INNER JOIN CountryLanguage ON Country.Code= CountryLanguage.CountryCode
WHERE Country.continent = 'Asia'
ORDER BY CountryLanguage.Percentage LIMIT 5;
mysql56> ALTER TABLE Country ADD KEY index_continent(continent);
Query OK, 0 rows affected (0.05 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql56> ALTER TABLE CountryLanguage
-> ADD KEY index_countrycode_percentage(countrycode, percentage);
Query OK, 0 rows affected (0.11 sec)
Records: 0 Duplicates: 0 Warnings: 0
これは残念ながらWHERE狙いのキーになる。
わかりますん。
86. JOIN de WHERE狙いのキー
mysql56> EXPLAIN SELECT Name, Language, Population, Percentage
-> FROM Country INNER JOIN CountryLanguage ON Country.Code= CountryLanguage.CountryCode
-> WHERE Country.continent = 'Asia'
-> ORDER BY Percentage LIMIT 5;
+----+-------------+-----------------+------+------------------------------+------------------------------+---------
+--------------------+------+--------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref
| rows | Extra |
+----+-------------+-----------------+------+------------------------------+------------------------------+---------
+--------------------+------+--------------------------------------------------------+
| 1 | SIMPLE | Country | ref | index_continent | index_continent | 33 | const
| 51 | Using index condition; Using temporary; Using filesort |
| 1 | SIMPLE | CountryLanguage | ref | index_countrycode_percentage | index_countrycode_percentage | 3 |
world.Country.Code | 2 | NULL |
+----+-------------+-----------------+------+------------------------------+------------------------------+---------
+--------------------+------+--------------------------------------------------------+
2 rows in set (0.00 sec)
* 外側のテーブルをインデックスで刈り込んで
* 内側のテーブルもインデックスで刈り込んで
* ソートバッファに詰め込み
* ループして
* クイックソートして先頭から5件取り出す
87. JOIN de WHERE狙いのキー
my $country_index_num = $country_index->{map}->{Asia};
my $country_rownum_array= $country_index->{index}->[$country_index_num];
foreach my $country_rownum (@$country_rownum_array)
{
my $country_row= $country_table->[$country_rownum];
$evaluted++;
my $language_index_num = $language_index->{map}->{$country_row->{code}}->{self};
my $language_index_range= $language_index->{index}->[$language_index_num];
foreach my $language_rownum_array (@$language_index_range)
{
foreach my $language_rownum (@$language_rownum_array)
{
my $language_row= $language_table->[$language_rownum];
$sorted++;
push(@{$sort_buffer->{$language_row->{percentage}}},
[$country_rownum, $language_rownum]);
}
}
}
ファイルソート以降は略
indexed_join_indexed_where_scan_orderby.pl
88. JOIN de WHERE狙いのキー
my $country_index_num = $country_index->{map}->{Asia};
my $country_rownum_array= $country_index->{index}->[$country_index_num];
foreach my $country_rownum (@$country_rownum_array)
{
my $country_row= $country_table->[$country_rownum];
$evaluted++;
my $language_index_num = $language_index->{map}->{$country_row->{code}}->{self};
my $language_index_range= $language_index->{index}->[$language_index_num];
foreach my $language_rownum_array (@$language_index_range)
{
foreach my $language_rownum (@$language_rownum_array)
{
my $language_row= $language_table->[$language_rownum];
$sorted++;
push(@{$sort_buffer->{$language_row->{percentage}}},
[$country_rownum, $language_rownum]);
}
}
}
ファイルソート以降は略
外側のテーブルを
WHEREで刈り込んで
indexed_join_indexed_where_scan_orderby.pl
89. JOIN de WHERE狙いのキーその1
my $country_index_num = $country_index->{map}->{Asia};
my $country_rownum_array= $country_index->{index}->[$country_index_num];
foreach my $country_rownum (@$country_rownum_array)
{
my $country_row= $country_table->[$country_rownum];
$evaluted++;
my $language_index_num = $language_index->{map}->{$country_row->{code}}->{self};
my $language_index_range= $language_index->{index}->[$language_index_num];
foreach my $language_rownum_array (@$language_index_range)
{
foreach my $language_rownum (@$language_rownum_array)
{
my $language_row= $language_table->[$language_rownum];
$sorted++;
push(@{$sort_buffer->{$language_row->{percentage}}},
[$country_rownum, $language_rownum]);
}
}
}
ファイルソート以降は略
刈り込んだ外側を
1行ずつキーにして
内側テーブルを刈り込む
indexed_join_indexed_where_scan_orderby.pl
90. JOIN de WHERE狙いのキー
my $country_index_num = $country_index->{map}->{Asia};
my $country_rownum_array= $country_index->{index}->[$country_index_num];
foreach my $country_rownum (@$country_rownum_array)
{
my $country_row= $country_table->[$country_rownum];
$evaluted++;
my $language_index_num = $language_index->{map}->{$country_row->{code}}->{self};
my $language_index_range= $language_index->{index}->[$language_index_num];
foreach my $language_rownum_array (@$language_index_range)
{
foreach my $language_rownum (@$language_rownum_array)
{
my $language_row= $language_table->[$language_rownum];
$sorted++;
push(@{$sort_buffer->{$language_row->{percentage}}},
[$country_rownum, $language_rownum]);
}
}
}
ファイルソート以降は略
内側まで刈り込んだら
ソートバッファに詰める
indexed_join_indexed_where_scan_orderby.pl
91. JOIN de WHERE狙いのキー
$ ./indexed_join_indexed_where_scan_orderby.pl
United Arab Emirates Hindi 2441000 0.000000
Bahrain English 617000 0.000000
Japan Ainu 126714000 0.000000
Kuwait English 1972000 0.000000
Lebanon French 3282000 0.000000
Total rows evaluted are 52, sorted are 239.
スキャンジョインよりよっぽどいいけど
そんなに効率が良いわけではなさそう
indexed_join_indexed_where_scan_orderby.pl
100. JOIN de WHERE狙いのキー
* 0.000000 Hindi ARE => ARE United Arab Emirates 2441000
* 0.000000 English BHR => BHR Bahrain 617000
* 0.000000 Ainu JPN => JPN Japan 126714000
* 0.000000 English KWT => KWT Kuwait 1972000
* 0.000000 French LBN => LBN Lebanon 3282000
* 0.000000 English MDV => MDV Maldives 286000
* 0.000000 Balochi OMN => OMN Oman 2542000
* 0.000000 Urdu QAT => QAT Qatar 599000
* 0.000000 Portuguese TMP => TMP East Timor 885000
* 0.000000 Sunda TMP => TMP East Timor 885000
* 0.000000 Soqutri YEM => YEM Yemen 18112000
* 0.100000 Garo BGD => BGD Bangladesh 129155000
* 0.100000 Khasi BGD => BGD Bangladesh 129155000
* 0.100000 Santhali BGD => BGD Bangladesh 129155000
* 0.100000 Tripuri BGD => BGD Bangladesh 129155000
* 0.100000 English JPN => JPN Japan 126714000
* 0.100000 Philippene Languages JPN => JPN Japan 126714000
* 0.100000 Chinese KOR => KOR South Korea 46844000
* 0.100000 Chinese PRK => PRK North Korea 24039000
* 0.200000 Marma BGD => BGD Bangladesh 129155000
* 0.200000 Dong CHN => CHN China 1277558000
* 0.200000 Puyi CHN => CHN China 1277558000
* 0.200000 Chinese JPN => JPN Japan 126714000
* 0.300000 Paiwan TWN => TWN Taiwan 22256000
* 0.400000 Chakma BGD => BGD Bangladesh 129155000
* 0.400000 Mongolian CHN => CHN China 1277558000
..
こっちがCountry
verbose_indexed_join_indexed_where_indexed_orderby.pl
こっちがCountryLanguage
101. JOIN de WHERE狙いのキー
* 0.000000 Hindi ARE => ARE United Arab Emirates 2441000
* 0.000000 English BHR => BHR Bahrain 617000
* 0.000000 Ainu JPN => JPN Japan 126714000
* 0.000000 English KWT => KWT Kuwait 1972000
* 0.000000 French LBN => LBN Lebanon 3282000
* 0.000000 English MDV => MDV Maldives 286000
* 0.000000 Balochi OMN => OMN Oman 2542000
* 0.000000 Urdu QAT => QAT Qatar 599000
* 0.000000 Portuguese TMP => TMP East Timor 885000
* 0.000000 Sunda TMP => TMP East Timor 885000
* 0.000000 Soqutri YEM => YEM Yemen 18112000
* 0.100000 Garo BGD => BGD Bangladesh 129155000
* 0.100000 Khasi BGD => BGD Bangladesh 129155000
* 0.100000 Santhali BGD => BGD Bangladesh 129155000
* 0.100000 Tripuri BGD => BGD Bangladesh 129155000
* 0.100000 English JPN => JPN Japan 126714000
* 0.100000 Philippene Languages JPN => JPN Japan 126714000
* 0.100000 Chinese KOR => KOR South Korea 46844000
* 0.100000 Chinese PRK => PRK North Korea 24039000
* 0.200000 Marma BGD => BGD Bangladesh 129155000
* 0.200000 ここでソーDong ト済みCHN であ=> っCHN て
China 1277558000
* 0.200000 Puyi CHN => CHN China 1277558000
* 0.200000 Chinese JPN => JPN Japan 126714000
* 0.300000 Paiwan TWN => TWN Taiwan 22256000
* 0.400000 Chakma BGD => BGD Bangladesh 129155000
* 0.400000 Mongolian CHN => CHN China 1277558000
..
verbose_indexed_join_indexed_where_indexed_orderby.pl
ほしいから
こっち向きに
結合してほしい
102. JOIN de ORDER BY狙いのキー
mysql56> ALTER TABLE Country ADD KEY index_code_continent(code, continent);
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql56> ALTER TABLE CountryLanguage ADD KEY index_percentage(percentage);
Query OK, 0 rows affected (0.07 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql56> EXPLAIN SELECT Name, Language, Population, Percentage
-> FROM CountryLanguage JOIN Country ON Country.Code= CountryLanguage.CountryCode
-> WHERE Country.continent = 'Asia'
-> ORDER BY Percentage LIMIT 5;
+----+-------------+-----------------+-------+----------------------+----------------------+---------
+-----------------------------------------+------+-----------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref
| rows | Extra |
+----+-------------+-----------------+-------+----------------------+----------------------+---------
+-----------------------------------------+------+-----------------------+
| 1 | SIMPLE | CountryLanguage | index | NULL | index_percentage | 4 | NULL
| 5 | NULL |
| 1 | SIMPLE | Country | ref | index_code_continent | index_code_continent | 36 |
world.CountryLanguage.CountryCode,const | 1 | Using index condition |
+----+-------------+-----------------+-------+----------------------+----------------------+---------
+-----------------------------------------+------+-----------------------+
2 rows in set (0.00 sec)
* 外側のテーブルはORDER BY狙いのキー
** ↑はただのJOINなれど、STRAIGHT_JOINした方がいい。
* 1行ごとにWHEREとONのカラムで評価
* 合計5行マッチしたら終了
103. JOIN de ORDER BY狙いのキー
my $language_cardinality= scalar(keys(%{$language_index->{map}}));
LOOP: for (my $language_index_num= 0;
$language_index_num < $language_cardinality;
$language_index_num++)
{
my $language_rownum_array= $language_index->{index}->[$language_index_num];
foreach my $language_rownum (@$language_rownum_array)
{
my $language_row= $language_table->[$language_rownum];
my $country_index_num_first= $country_index->{map}->{$language_row->{countrycode}}->{self};
my $country_index_num_second= $country_index->{map}->{$language_row->{countrycode}}->{Asia};
if (!(defined($country_index_num_second)))
{next;}
my $country_rownum_array=
$country_index->{index}->[$country_index_num_first]->[$country_index_num_second];
foreach my $country_rownum (@$country_rownum_array)
{
my $country_row= $country_table->[$country_rownum];
printf("%st%st%dt%fn",
$country_row->{name},
$language_row->{language},
$country_row->{population},
$language_row->{percentage});
if (++$count >= 5)
{last LOOP;}
}
}
}
indexed_join_indexed_where_indexed_orderby.pl
104. JOIN de ORDER BY狙いのキー
my $language_cardinality= scalar(keys(%{$language_index->{map}}));
LOOP: for (my $language_index_num= 0;
$language_index_num < $language_cardinality;
$language_index_num++)
{
my $language_rownum_array= $language_index->{index}->[$language_index_num];
foreach my $language_rownum (@$language_rownum_array)
{
my $language_row= $language_table->[$language_rownum];
my $country_index_num_first= $country_index->{map}->{$language_row->{countrycode}}->{self};
my $country_index_num_second= $country_index->{map}->{$language_row->{countrycode}}->{Asia};
if (!(defined($country_index_num_second)))
{next;}
my $country_rownum_array=
$country_index->{index}->[$country_index_num_first]->[$country_index_num_second];
foreach my $country_rownum (@$country_rownum_array)
{
my $country_row= $country_table->[$country_rownum];
printf("%st%st%dt%fn",
$country_row->{name},
$language_row->{language},
$country_row->{population},
$language_row->{percentage});
if (++$count >= 5)
{last LOOP;}
}
}
}
外側のテーブルには
ORDER BY狙いのキー
indexed_join_indexed_where_indexed_orderby.pl
105. JOIN de ORDER BY狙いのキー
my $language_cardinality= scalar(keys(%{$language_index->{map}}));
LOOP: for (my $language_index_num= 0;
$language_index_num < $language_cardinality;
$language_index_num++)
{
my $language_rownum_array= $language_index->{index}->[$language_index_num];
foreach my $language_rownum (@$language_rownum_array)
{
my $language_row= $language_table->[$language_rownum];
my $country_index_num_first= $country_index->{map}->{$language_row->{countrycode}}->{self};
my $country_index_num_second= $country_index->{map}->{$language_row->{countrycode}}->{Asia};
if (!(defined($country_index_num_second)))
{next;}
my $country_rownum_array=
$country_index->{index}->[$country_index_num_first]->[$country_index_num_second];
foreach my $country_rownum (@$country_rownum_array)
{
my $country_row= $country_table->[$country_rownum];
printf("%st%st%dt%fn",
$country_row->{name},
$language_row->{language},
$country_row->{population},
$language_row->{percentage});
if (++$count >= 5)
{last LOOP;}
}
}
}
内側のテーブルは
WHERE狙いのキー
indexed_join_indexed_where_indexed_orderby.pl
106. WHERE狙いのキー
ORDER BY狙いのキー
● もちろん両方狙えるインデックスを作っていく
のが最良。
● ただし必ずしも一番良いキーでWHEREとORDER BY
を両方狙い打ちできるとは限らない。
● どっちがどういう動作になるかがイメージできれ
ば、打ち分けるのはそう難しくない
● ちゃんと狙ったクエリーとそうでないクエリーは
100倍くらい性能が違うこともザラ。