Легенда:
новое сообщение
закрытая нитка
новое сообщение
в закрытой нитке
старое сообщение
|
- Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
- Новичкам также крайне полезно ознакомиться с данным документом.
Отнюдь ) при использовании between индексы используюся активно. Кстати говоря напоминаю, что есть очень удобный инструмент анализа запросов. имя ему `describe` ;)[upd] 01.03.11 23:06 Число просмотров: 1489
Автор: kstati <Евгений Борисов> Статус: Elderman Отредактировано 02.03.11 01:15 Количество правок: 14
|
Одна из задач индексов - быстрая сортировка значений для выборки.
В случае использования between по индексированному полю идёт поиск малого значения, затем выдача результата вплоть до большего значения.
Выгода очевидна, по скорости. А причина - количество затрагиваемых строк (в моём случае 30480 против 762707), которые обусловлены типом запроса range и index соответственно; При этом вариант "where YEAR(`d`) " даже не пытается использовать ключи.
Теста ради набил таблицу хламом - случайными датами за 50 лет:
insert into tests.date_test values (NOW() - interval floor(rand()*365*50) day);
А за тем выбрал данные за 2001 год.
Если работа ведётся именно с диапазоном, то between рулит. Ясное дело, если нужно выбрать к примеру все первые числа, то ой )
mysql> describe date_test;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| d | date | YES | MUL | NULL | |
+-------+------+------+-----+---------+-------+
1 row in set (0.00 sec)
mysql> select distinct count(*) from date_test;
+----------+
| count(*) |
+----------+
| 762061 |
+----------+
1 row in set (0.77 sec)
mysql> select count(*) from date_test where YEAR(`d`) = 2001;
+----------+
| count(*) |
+----------+
| 15401 |
+----------+
1 row in set (0.80 sec)
mysql> select count(*) from date_test where `d` like "2001%";
+----------+
| count(*) |
+----------+
| 15401 |
+----------+
1 row in set, 1 warning (0.84 sec)
mysql> select count(*) from date_test where `d` between '2001-01-01' and '2001-12-31';
+----------+
| count(*) |
+----------+
| 15401 |
+----------+
1 row in set (0.02 sec)
mysql> describe select count(*) from date_test where `d` between '2001-01-01' and '2001-12-31';
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
| 1 | SIMPLE | date_test | range | i | i | 4 | NULL | 30480 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
1 row in set (0.00 sec)
mysql> describe select count(*) from date_test where YEAR(`d`) = 2001;
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| 1 | SIMPLE | date_test | index | NULL | i | 4 | NULL | 762707 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
mysql> describe select count(*) from date_test where `d` like "2001%";
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| 1 | SIMPLE | date_test | index | i | i | 4 | NULL | 762707 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
1 row in set, 1 warning (0.00 sec)
---
[upd] Как и ожидал between даёт эффект и при работе с or.
То есть поиск данных за определённый месяц тоже работает на ура, хотя выгода по времени уже не на столько заметна.
<?
$sql = "select count(*) from date_test where ";
$tmp = array();
for ($i=1961; $i<=2011; $i++) {
$tmp[] = "`d` between '$i-01-01' and '$i-01-31'";
}
$sql .= join(" or ", $tmp);
?> ---
Преобразуется в длиннющий запрос:
select count(*) from date_test where `d` between '1961-01-01' and '1961-01-31' or ... or `d` between '2011-01-01' and '2011-01-31
select count(*) from date_test where `d` between '1961-01-01'....<откусил>
+----------+
| count(*) |
+----------+
| 64615 |
+----------+
1 row in set (0.45 sec)
mysql> describe select count(*) from date_test where `d`...<откусил>
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
| 1 | SIMPLE | date_test | range | i | i | 4 | NULL | 64566 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+-------+--------------------------+
1 row in set (0.00 sec)
mysql> select count(*) from date_test where d like __01%';
+----------+
| count(*) |
+----------+
| 64615 |
+----------+
1 row in set, 1 warning (0.92 sec)
mysql> describe select count(*) from date_test where d like __01%';
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
| 1 | SIMPLE | date_test | index | NULL | i | 4 | NULL | 762561 | Using where; Using index |
+----+-------------+-----------+-------+---------------+------+---------+------+--------+--------------------------+
1 row in set, 1 warning (0.00 sec) ---
В общем, не стоит отмахиваться от between ) реально удобно и быстро.
И, кстати, если внимательно приглядеться к выборке длиннющим запросом, то количество затрагиваемых тестами строк меньше чем количество результирующих строк. Сильно копошиться ломает, но предполагаю, что дело в бинарном поиске.
|
|
|