информационная безопасность
без паники и всерьез
 подробно о проектеRambler's Top100
Все любят медSpanning Tree Protocol: недокументированное применение
BugTraq.Ru
Русский BugTraq
 Анализ криптографических сетевых... 
 Модель надежности двухузлового... 
 Специальные марковские модели надежности... 
 Три миллиона электронных замков... 
 Doom на газонокосилках 
 Умер Никлаус Вирт 
главная обзор RSN блог библиотека закон бред форум dnet о проекте
bugtraq.ru / форум / programming
Имя Пароль
ФОРУМ
все доски
FAQ
IRC
новые сообщения
site updates
guestbook
beginners
sysadmin
programming
operating systems
theory
web building
software
hardware
networking
law
hacking
gadgets
job
dnet
humor
miscellaneous
scrap
регистрация





Легенда:
  новое сообщение
  закрытая нитка
  новое сообщение
  в закрытой нитке
  старое сообщение
  • Напоминаю, что масса вопросов по функционированию форума снимается после прочтения его описания.
  • Новичкам также крайне полезно ознакомиться с данным документом.
Отнюдь ) при использовании between индексы используюся активно. Кстати говоря напоминаю, что есть очень удобный инструмент анализа запросов. имя ему `describe` ;)[upd] 01.03.11 23:06  Число просмотров: 1554
Автор: 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 ) реально удобно и быстро.
И, кстати, если внимательно приглядеться к выборке длиннющим запросом, то количество затрагиваемых тестами строк меньше чем количество результирующих строк. Сильно копошиться ломает, но предполагаю, что дело в бинарном поиске.
<programming> Поиск 






Rambler's Top100
Рейтинг@Mail.ru


  Copyright © 2001-2024 Dmitry Leonov   Page build time: 0 s   Design: Vadim Derkach