2015-03-24 2 views
1

Я пытаюсь выяснить, наиболее эффективный способ извлечения значений из базы данных, которая имеет структуру, подобную этой:MySQL индексации столбцов против присоединения таблиц

тестовая таблица:

int id (primary, auto increment) 
varchar(50) stuff, 
varchar(50) important_stuff; 

где нужно сделать запрос как

select * from test where important_stuff like 'prefix%'; 

размер всей таблицы составляет примерно 10 миллионов строк, однако есть только около 500-1000 различных значений для important_stuff. Мое текущее решение - индексирование important_stuff, однако производительность не является удовлетворительной. Будет ли лучше создать отдельную таблицу, которая будет соответствовать отчетливое important_stuff к определенному идентификатору, который будет храниться в таблице «тест», а затем сделать

(select id from stuff_lookup where important_stuff like 'prefix%') a join select * from test b where b.stuff_id=a.id

или это:

select * from test where stuff_id exists in(select id from stuff_lookup where important_stuff like 'prefix%')

Каков наилучший способ оптимизации таких вещей?

+1

Какие dbms вы используете? mysql <> sqlserver –

+0

MySQL с InnoDB – Dimi

+0

Это похоже на ситуацию, когда некоторые руки на тестировании будут вам полезны. Попробуйте создать вторую таблицу, а затем попробуйте использовать два тестовых примера использования и посмотрите, какая из них работает лучше. Я не могу говорить ни для кого, но у меня нет 10-миллионной тестовой базы данных, лежащей рядом с тестом;) – mituw16

ответ

1

Сколько стоит innodb_buffer_pool_size? Сколько оперативной памяти доступно? Первый должен составлять около 70% от последнего. Вы увидите через минуту, почему я поднимаю эту настройку.

Основываясь на ваших 3 предлагаемых SELECT, оригинал будет работать так же хорошо, как два сложных. В некотором другом случае сложная формулировка может работать лучше.

INDEX(important_stuff) является «лучшим» показателем для

select * from test where important_stuff like 'prefix%'; 

Теперь, давайте изучим, как этот запрос работает с этим индексом:

  1. Reach в индекс ВТКЕЯ, начиная с «приставкой». (Усилия: практически мгновенно)
  2. Сканирование вперед, скажем, 1000 записей. Это будет около 10 блоков InnoDB (по 16 КБ каждый). Каждая запись будет иметь ПЕРВИЧНЫЙ КЛЮЧ (id). (Усиление: < = 10 дисков)
  3. Для каждой записи найдите строку (так что вы можете получить «*»). Это 1000 PK-запросов в BTree, которые содержат как PK, так и данные. В лучшем случае все они могут быть в 10 блоках. В худшем случае они могут быть в 1000 отдельных блоков. (Усиление: 10-1000 блоков)

Всего усилий: ~ 1010 блоков (наихудший случай).

Стандартный вращающийся диск может обрабатывать ~ 100 раз в секунду. Так. мы смотрим 10 секунд.

Теперь запустите запрос еще раз. Угадай, что; все эти блоки теперь находятся в ОЗУ (кэшируются в «buffer_pool», который , надеюсь, достаточно большой для всех них). И он работает менее чем за 1 секунду.

OPTIMIZE TABLE был нет необходимо! Это было не обновление статистики, а кэширование, что ускорило запрос.

1

Я не пользователь MySQL, но я провел несколько тестов в своей локальной базе данных. Я добавил 10 миллионов строк, как вы писали, и отдельные данные из третьего столбца загружаются довольно быстро. Это мои результаты.

mysql> describe bigtable; 
+-----------------+-------------+------+-----+---------+----------------+ 
| Field   | Type  | Null | Key | Default | Extra   | 
+-----------------+-------------+------+-----+---------+----------------+ 
| id    | int(11)  | NO | PRI | NULL | auto_increment | 
| stuff   | varchar(50) | NO |  | NULL |    | 
| important_stuff | varchar(50) | NO | MUL | NULL |    | 
+-----------------+-------------+------+-----+---------+----------------+ 
3 rows in set (0.03 sec) 

mysql> select count(*) from bigtable; 
+----------+ 
| count(*) | 
+----------+ 
| 10000089 | 
+----------+ 
1 row in set (2.87 sec) 

mysql> select count(distinct important_stuff) from bigtable; 
+---------------------------------+ 
| count(distinct important_stuff) | 
+---------------------------------+ 
|       1000 | 
+---------------------------------+ 
1 row in set (0.01 sec) 

mysql> select distinct important_stuff from bigtable; 
.... 
| is_987   | 
| is_988   | 
| is_989   | 
| is_99   | 
| is_990   | 
| is_991   | 
| is_992   | 
| is_993   | 
| is_994   | 
| is_995   | 
| is_996   | 
| is_997   | 
| is_998   | 
| is_999   | 
+-----------------+ 
1000 rows in set (0.15 sec) 

Важная информация является то, что я освежил статистику по этой таблице (перед этой операцией мне нужно ~ 10 секунд, чтобы загрузить эти данные).

mysql> optimize table bigtable; 
+0

'ANALYZE TABLE' обновит статистику, не перестраивая таблицу. –

Смежные вопросы