2014-09-26 1 views
0

У меня есть хранимая процедура (предоставленная ниже), которую я написал для обработки около 25 миллионов записей. Эта эта хранимая процедура выполняет задание lat & lon, расстояние (25 миль) и количество записей для присвоения (12), найти все записи, находящиеся в данных границах на основе 25 миль, и назначить до 12 записей пользователю, у которого еще нет записей. И пользователь может иметь только одну запись для каждой категории (так что 12 записей с отдельной категорией).MySQL хранит proc - Обработка миллионов записей - как ускорить

Хранимая процедура отлично работает. Единственная проблема - это длиться долго. Я создаю 8 общих проков, каждый из которых идентичен, за исключением рабочей таблицы (POSTSINAREATBL [1-8]), поэтому я могу ускорить процесс. У меня были скрипты, работающие в течение 4 дней, и обработали только 3,5 миллиона из 25 миллионов записей.

Я надеюсь, что у кого-то может быть некоторое понимание и помощь в том, как ускорить это. Мне действительно нужно получить все записи, обработанные в течение следующих 1-2 дней, и по курсу, который он собирается сейчас, это займет почти месяц!

Кроме того, с 8 сценариями, у меня есть процессор, работающий на 99,8%, поэтому я на максимальной емкости.

DELIMITER $$ 

CREATE PROCEDURE `get_pins_in_boundaries`(IN mylon double, IN mylat double, IN dist int, IN numrecords int) 
BEGIN 
    declare isDone INT; 

    declare lat float; 
    declare lng float; 

    declare lon1 float; 
    declare lon2 float; 
    declare lat1 float; 
    declare lat2 float; 

    declare this_iter_pin_id int; 
    declare use_this_user_id int; 

    DECLARE num_results_in_area int; 

    DECLARE cur_posts_to_assign_to_user CURSOR FOR select pin_id from POSTSINAREATBL group by category_id limit numrecords; 

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET isDone = 1; 

    IF mylon = 0.000000 OR mylat = 0.000000 THEN 
     SELECT CONCAT('complete') AS results; 
    ELSE 

     SET lat=mylon; 
     SET lng=mylat; 

     -- calculate lon and lat for the rectangle: 
     set lon1 = mylon-dist/abs(cos(radians(mylat))*69); 
     set lon2 = mylon+dist/abs(cos(radians(mylat))*69); 
     set lat1 = mylat-(dist/69); set lat2 = mylat+(dist/69); 

     -- calculate lon and lat for the rectangle: 
     set lon1 = lng - dist/ABS(COS(RADIANS(lat)) * 111.04); 
     set lon2 = lng + dist/ABS(COS(RADIANS(lat)) * 111.04); 
     set lat1 = lat - dist/(111.04); 
     set lat2 = lat + dist/(111.04); 

     -- create temp table and store records matching criteria into table 
     CREATE TABLE IF NOT EXISTS POSTSINAREATBL(
      pin_id BIGINT NOT NULL, 
      category_id BIGINT NOT NULL, 
      distance DECIMAL(6,1) 
     ); 

     INSERT INTO POSTSINAREATBL (
      SELECT pin_id,category_id, (3959 * acos(cos(radians(lat)) * cos(radians(latitude)) * cos(radians(longitude) - radians(lng)) + sin(radians(lat)) * sin(radians(latitude)))) as distance 
      FROM skoovy_prd.pins 
      WHERE longitude between lon1 and lon2 
      and latitude between lat1 and lat2 
      and user_id =0 
     ); 

     select count(*) INTO num_results_in_area from POSTSINAREATBL; 

     WHILE num_results_in_area > 0 DO 

      SET use_this_user_id = (SELECT user_id from skoovy_prd.users WHERE user_id NOT IN(select user_id from skoovy_prd.posts_users_processed) LIMIT 1); 

      INSERT INTO skoovy_prd.posts_users_processed (user_id) VALUES(use_this_user_id); 

      SET isDone = 0; 
      OPEN cur_posts_to_assign_to_user; 
      REPEAT 
       FETCH cur_posts_to_assign_to_user INTO this_iter_pin_id; 

       UPDATE skoovy_prd.pins SET pins.user_id = use_this_user_id WHERE pins.pin_id = this_iter_pin_id; 

       DELETE FROM POSTSINAREATBL WHERE pin_id = this_iter_pin_id; 

       SET num_results_in_area = num_results_in_area - 1; 

      UNTIL isDone END REPEAT; 

      CLOSE cur_posts_to_assign_to_user; 

     END WHILE; 

     TRUNCATE TABLE POSTSINAREATBL; 

     SELECT CONCAT('complete') AS results; 

    END IF; 

END 

ответ

0

Пробовали ли вы применять spartial индекс? Я не пробовал это на mysql, но для postgresql есть расширение postgis, которое предоставляет полный набор полезных функций для таких задач. Это реально помогает мне в одной и той же задаче. http://postgis.net/

Проверить это один http://dev.mysql.com/doc/refman/5.0/en/spatial-extensions.html

+0

Спасибо. Я запустил несколько тестов, и не кажется, что проблема «проблема» в запросе для данных в диапазонах геолокации. – kambythet

+0

Если вы хотите найти узкое место вашей хранимой процедуры, запустите «объяснять» для каждого запроса в вашей процедуре. После того, как вы найдете проблему, просто оптимизируйте ее, используя индексы. http://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html – xardas

+0

Готово уже. Дело не в том, что отсутствуют индексы, индексы не используются должным образом и т. Д. Это то, что есть миллионы записей, и я пытаюсь понять, может быть, есть более эффективный способ сделать это и быстро выполнить действия, которые в настоящее время выполняет proc выполнения. – kambythet