|
|
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
Приветствую, Уважаемые! Столкнулся с задачей привязки геокоординат к объектам КЛАДР, все прошло гладко с регионами, районами, городами, п, д. и т.д. Но на моменте парсинга координат для улиц, после прохода 110 тыс. записей, скорость снизилась катастрофически. До вышеприведённой отметки скорость устраивала, в день обрабатывалось до 100 тыс. адресных объектов(регионы, районы, города), запрос составлял 0.047, теперь составляет 0.732, а иногда и секунду и более вовсе. Ключи всем таблицам присвоены по тем полям, по которым происходит поиск, сравнение и сортировка, тип таблиц InnoDB, сама база КЛАДР изменена, регионы, районы, города, улицы вынесены в отдельные таблицы, в каждой таблице созданы поля связывающие таблица между собой на основе КЛАДР, ну т.е. все очень просто и банально, поэтому не могу понять, где собака зарылась. Прошу советов у знающих. Структура базы: -- -- Структура таблицы `cities` -- CREATE TABLE IF NOT EXISTS `cities` ( `Id` bigint(13) DEFAULT NULL, `Name` varchar(78) DEFAULT NULL, `ZipCode` varchar(6) DEFAULT NULL, `TypeShort` varchar(20) DEFAULT NULL, `Okato` varchar(11) DEFAULT NULL, `Type` varchar(54) DEFAULT NULL, `CodeRegion` smallint(2) DEFAULT NULL, `CodeDistrict` smallint(3) DEFAULT NULL, `CodeCity` smallint(4) DEFAULT NULL, `CodeStreet` int(1) DEFAULT NULL, `CodeBuilding` int(1) DEFAULT NULL, `Sort` int(6) DEFAULT NULL, `TypeCode` int(1) DEFAULT NULL, `Bad` varchar(15) DEFAULT NULL, `Points` varchar(30) NOT NULL, `check` char(1) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- -- Структура таблицы `district` -- CREATE TABLE IF NOT EXISTS `district` ( `Id` bigint(13) DEFAULT NULL, `Name` varchar(68) DEFAULT NULL, `ZipCode` varchar(6) DEFAULT NULL, `TypeShort` varchar(20) DEFAULT NULL, `Okato` varchar(11) DEFAULT NULL, `Type` varchar(54) DEFAULT NULL, `CodeRegion` smallint(2) DEFAULT NULL, `CodeDistrict` smallint(3) DEFAULT NULL, `CodeCity` int(1) DEFAULT NULL, `CodeStreet` int(1) DEFAULT NULL, `CodeBuilding` int(1) DEFAULT NULL, `Sort` int(5) DEFAULT NULL, `TypeCode` int(1) DEFAULT NULL, `Bad` varchar(15) DEFAULT NULL, `Points` varchar(30) NOT NULL, `check` char(1) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- -- Структура таблицы `regions` -- CREATE TABLE IF NOT EXISTS `regions` ( `Id` bigint(13) DEFAULT NULL, `Name` varchar(74) DEFAULT NULL, `ZipCode` varchar(6) DEFAULT NULL, `TypeShort` varchar(20) DEFAULT NULL, `Okato` bigint(11) DEFAULT NULL, `Type` varchar(54) DEFAULT NULL, `CodeRegion` smallint(2) DEFAULT NULL, `CodeDistrict` int(1) DEFAULT NULL, `CodeCity` int(1) DEFAULT NULL, `CodeStreet` int(1) DEFAULT NULL, `CodeBuilding` int(1) DEFAULT NULL, `Sort` int(6) DEFAULT NULL, `TypeCode` int(1) DEFAULT NULL, `Bad` varchar(15) DEFAULT NULL, `Points` varchar(30) NOT NULL, `check` char(1) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- -- Структура таблицы `streets` -- CREATE TABLE IF NOT EXISTS `streets` ( `Id` bigint(17) DEFAULT NULL, `Name` varchar(78) DEFAULT NULL, `ZipCode` varchar(6) DEFAULT NULL, `TypeShort` varchar(20) DEFAULT NULL, `Okato` varchar(11) DEFAULT NULL, `Type` varchar(55) DEFAULT NULL, `Bad` varchar(15) DEFAULT NULL, `CodeRegion` smallint(2) DEFAULT NULL, `CodeDistrict` smallint(3) DEFAULT NULL, `CodeCity` smallint(4) DEFAULT NULL, `CodeStreet` int(4) DEFAULT NULL, `CodeBuilding` int(1) DEFAULT NULL, `Points` varchar(30) NOT NULL, `check` char(1) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Индексы сохранённых таблиц -- -- -- Индексы таблицы `cities` -- ALTER TABLE `cities` ADD KEY `CodeRegion` (`CodeRegion`), ADD KEY `CodeCity` (`CodeCity`), ADD KEY `CodeStreet` (`CodeStreet`), ADD KEY `Points` (`Points`), ADD KEY `Id` (`Id`), ADD KEY `CodeDistrict` (`CodeDistrict`); -- -- Индексы таблицы `district` -- ALTER TABLE `district` ADD KEY `Id` (`Id`), ADD KEY `CodeRegion` (`CodeRegion`), ADD KEY `CodeDistrict` (`CodeDistrict`), ADD KEY `Points` (`Points`), ADD KEY `check` (`check`), ADD KEY `TypeShort` (`TypeShort`); -- -- Индексы таблицы `regions` -- ALTER TABLE `regions` ADD KEY `Id` (`Id`), ADD KEY `CodeRegion` (`CodeRegion`), ADD KEY `Points` (`Points`), ADD KEY `check` (`check`), ADD KEY `TypeShort` (`TypeShort`); -- -- Индексы таблицы `streets` -- ALTER TABLE `streets` ADD KEY `Id` (`Id`), ADD KEY `TypeShort` (`TypeShort`), ADD KEY `CodeRegion` (`CodeRegion`), ADD KEY `CodeDistrict` (`CodeDistrict`), ADD KEY `CodeCity` (`CodeCity`), ADD KEY `CodeStreet` (`CodeStreet`), ADD KEY `Points` (`Points`), ADD KEY `check` (`check`); Запрос: SELECT S.Id AS Id, S.TypeShort AS t_s, S.Name AS street, R.TypeShort AS t_r, R.Name AS region, D.Name AS rayon, D.TypeShort AS t_d, C.TypeShort AS t_c, C.Name AS city FROM streets S, regions R, district D, cities C" WHERE S.check = '0' AND S.CodeRegion != 0 AND S.CodeDistrict != 0 AND S.CodeCity != 0 AND R.CodeRegion = S.CodeRegion AND D.CodeRegion = S.CodeRegion AND D.CodeDistrict = S.CodeDistrict AND C.CodeRegion = S.CodeRegion AND C.CodeDistrict = S.CodeDistrict AND C.CodeCity = S.CodeCity ORDER BY S.Id DESC LIMIT 1; Да, все это делается на локальном компе с вин8, но пробовал то же самое проделать на ubuntu, результат не меняется, таблица cities жутко тормозит запрос, если её исключаю, то скорость в десятки раз возрастает. Хотя все ключи по нужным полям проставлены. Буду рад любому совету. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 07:03:48 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
ramha, где у тебя хоть один первичный ключь? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 08:15:04 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
ramha, хорошее простое решение было в этом форуме - КЛАДР доработать - добавить поле категории - (допустим, область - 1, район - 2, город - 3 улица - 4) для фильтрации. Нет необходимости держать свою структуру, работа напрямую со стандартным КЛАДР (с добавленным полем) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 08:44:02 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
нашел, хорошо что засунул в избранное, спасибо RXL Улучшить скорость запроса ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 09:03:50 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
MasterZiv, повесил сейчас первичный на Id в таблице cities, и в streets, скорость улучшилась, но буквально на 0.1. теперь запрос выполняется 0.62813777923584), что уже лучше, но все равно очень замедляет весь процесс в разы. Попробую создать аналогичную таблицу с другим названием, перенести туда все записи, у которых уже есть координаты, удалить их из старой таблицы, и новые парсить уже по такому же принципу. Alex_Ustinov, Так у меня же похоже сделано, просто мне такой вариант показался удобным, чтобы все хранилось в разных таблицах, но не подумал, правда, о производительности при склейке) Но благодарю, если не получится добиться приемлемой скорости с удалением обработанной записи из основной таблицы и переносом её в новую, то обязательно воспользуюсь этой реализацией. Благодарю всех за участие, пойду биться дальше) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 09:36:09 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
ramha, пробуйте составные индексы, MySQL не использует несколько индексов для одной таблицы. Допустим (CodeRegion,CodeDistrict) смотрите EXPLAIN запроса, какой оптимальный индекс выбрал MySQL. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 09:47:27 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
Alex_Ustinov, странно, но у меня работают сразу по 3 индексам вроде, так как если одного из полей ключ снять, то запрос начинает чуть ли не в сотни раз дольше выполняться. Но решение все же решил быстренько на php накидать, как и планировал с переносом данных в новую таблицу, конечно больше телодвижений, но по-времени в любом случае экономлю, так как запросы теперь выполняются по 0.007 сек) Кому нужно решение для похожих задач на php, прикрепляю содержимое 2-х файлов, index.php и import.php Скрипт может конвертировать базы любого размера на самом бюджетном хостинге за счет jquery $.get. index.php <!DOCTYPE html> <html lang="ru"> <head> <meta charset="utf-8" /> <!-- на всякий случай обновляю каждую минуту index.php--> <META HTTP-EQUIV='Refresh' CONTENT='60; URL=index.php'> <title>importDB</title> <script src=" http://code.jquery.com/jquery-2.0.3.js"></script> <script> setTimeout(F1, 10); function F1(){ $.get('import.php', function(data){ $('#html').html(data); }); setTimeout(F1, 100); } </script> </head> <body> <div id=html></div> </body> </html> import.php <? set_time_limit(0); define('_DB_HOST', 'localhost'); define('_DB_USER', 'root'); define('_DB_PASS', ''); define('_DB_NAME', 'geo_kladr'); define('_DB_PREX', ''); require_once( $_SERVER['DOCUMENT_ROOT'].'/class/db.php' ); $db = new database( _DB_HOST, _DB_USER, _DB_PASS, _DB_NAME, _DB_PREX ); switch ($o){ case 'import_db': import_db(); break; default: for($i=0; $i< 5; $i++) { import_db(); } break; } function import_db() { global $db; $query = "SELECT * FROM `streets` WHERE `check` = '1' ORDER BY Id ASC LIMIT 1"; $db->setQuery($query); $rows = $db->loadObjectList(); if (count($rows) != 0) { foreach ($rows as $row) { $query_insert = "INSERT INTO `streets_test` (`Id`, `Name`, `ZipCode`, `TypeShort`, `Okato`, `Type`, `Bad`, `CodeRegion`, `CodeDistrict`, `CodeCity`, `CodeStreet`, `CodeBuilding`, `Points`, `check`) VALUES ( '$row->Id', '$row->Name', '$row->ZipCode', '$row->TypeShort', '$row->Okato', '$row->Type', '$row->Bad', '$row->CodeRegion', '$row->CodeDistrict', '$row->CodeCity', '$row->CodeStreet', '$row->CodeBuilding', '$row->Points', '$row->check');"; $db->setQuery($query_insert); if( !$db->query() ) { echo $content = 'Ошибка: не удалось вставить запись '.$row->Id." в таблицу streets_test\n"; $log = file_get_contents($_SERVER['DOCUMENT_ROOT'].'/log.txt'); $log .= $content; file_put_contents($_SERVER['DOCUMENT_ROOT'].'/log.txt', $log ); } else { $db->setQuery("DELETE FROM `streets` WHERE `Id` = '$row->Id';"); if( !$db->query() ) { echo $content = 'Ошибка: не удалось удалить запись '.$row->Id." из таблицы streets\n"; $log = file_get_contents($_SERVER['DOCUMENT_ROOT'].'/log.txt'); $log .= $content; file_put_contents($_SERVER['DOCUMENT_ROOT'].'/log.txt', $log ); } else { echo $content = 'Успех '.$row->Id; echo '<br>'; } } } } else { echo $content = 'Импорт завершён.'; } } ?> ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 12:36:55 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
Alex_Ustinov, Решил всё же попробовать и Ваш совет и результат впечатляет!) Благодарю за подсказку о комбинированных индексах! Решение было в этой строке(: ALTER TABLE `cities` ADD KEY `combined` (`CodeRegion`,`CodeDistrict`,`CodeCity`); ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 14.04.2015, 22:19:34 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
Приветствую всех! Эх, зря была проделана работа по сбору координат) Выяснилось, что накосячил со столбцом CodeCity задав ему тип smallint, не посмотрев предварительно какие именно максимальные значения содержатся в этом столбце, а ограничил лишь 6-ю символами колонку, а в итоге в ней оказывается были числа более 32000, и они все превратились в максимально допустимый размер) Но ладно, боевой дух не угас продолжать дальше, всё делаю теперь по новой, учитывая пред. опыт. Но теперь не помогают комбинированные индексы, как только не пробовал, и раздельные тоже пробовал на каждое используемое поле в таблицах вешать, запрос тормозит после прохода 80 тыс. записей с 0.01 до 0.3, причём пришлось убрать order by по Id, с ним запрос вообще выполняется 5 сек. Вот explain: А вот сам запрос: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. На streets.Points повешан индекс ограниченный 1-м символом, это сделано для того, чтобы проверять есть ли координаты у записи, если нет, то парсить. Запрос тормозит таблица district почему-то, хотя в ней всего 1800+ записей, если её исключить из запроса, то скорость возрастает в десятки раз сразу. Что же не так в запросе-то? Есть ли какие-нибудь идеи люди умные?) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.04.2015, 16:42:17 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
И вот, кстати, еще немного обновлённая структура базы и индексов. Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.04.2015, 16:49:07 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
Попробовал перестроить порядок выборки, не со streets, а с regions строить запрос, ситуация улучшилась, теперь задействованы все индексы из всех таблиц, запрос ускорился на 0.2, теперь выполняется 0.1, наверно на большую скорость уже можно и не рассчитывать учитывая размеры кладра, но на всякий случай прикреплю как explain, вдруг у кого-нибудь появятся еще какие-нибудь идеи.) Запрос: SELECT R.TypeShort AS t_r, R.Name AS region, R.TypeCode AS TypeCode, D.Name AS rayon, D.TypeShort AS t_d, C.TypeShort AS t_c, C.Name AS city, S.Name, S.kID FROM regions R, district D, cities C, streets S WHERE S.CodeRegion = R.CodeRegion AND D.CodeRegion = R.CodeRegion AND C.CodeRegion = D.CodeRegion AND C.CodeDistrict = D.CodeDistrict AND S.CodeCity = C.CodeCity AND S.Points = '' LIMIT 1; EXPLAIN: ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.04.2015, 20:54:09 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
а если использовать join'ы в запросе ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 28.04.2015, 21:06:58 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
limit без order by вот и томозит. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.04.2015, 00:35:53 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
ScareCrowlimit без order by вот и томозит.а вот с этого места поподробней, пожалуйста ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.04.2015, 07:16:24 |
|
||
|
Ускорение выборки из базы КЛАДР для парсинга геокоординат
|
|||
|---|---|---|---|
|
#18+
Благодарю всех! mini.weblab, С джоинами по-быстрее вроде стало, переписал запрос так: Код: sql 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. Выполняется 0.1 - 0.2 сек, но уже обработано 200 строк, а до переписывания на джоины уже и по 0.7 сек выполнялся, так что Ваш совет как раз кстати, еще раз благодарю! :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 29.04.2015, 14:21:32 |
|
||
|
|

start [/forum/topic.php?fid=47&msg=38935556&tid=1833257]: |
0ms |
get settings: |
5ms |
get forum list: |
9ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
137ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
61ms |
get tp. blocked users: |
2ms |
| others: | 193ms |
| total: | 426ms |

| 0 / 0 |
