would-you-study-with-me / siksa-clock

째깍식사 : 밥 먹는데 헛걸음을 하지 않도록 선택을 도와주는 것
1 stars 0 forks source link

137 bug merge code | 엔드포인트 하나로 만들고 쿼리 최적화 #138

Closed hyeonprojects closed 1 year ago

hyeonprojects commented 1 year ago

한일

쿼리 안 돌아가는 이유

MariaDB는 비교적 최근 버전에 좌표 관련 기능을 지원해서 MariaDB 업데이트 했습니다.

쿼리 최적화 방법

필요없는 JOIN을 하나 없앰. (단순하죠?)

아래가 기본 ORM에서 나오는 쿼리문입니다.

SELECT anon_1.restaurant_id,
       anon_1.restaurant_name,
       anon_1.restaurant_rate,
       anon_1.restaurant_category,
       anon_1.restaurant_count_seats,
       anon_1.restaurant_x,
       anon_1.restaurant_y,
       anon_1.restaurant_address,
       anon_1.restaurant_description,
       anon_1.restaurant_contact,
       anon_1.restaurant_created_at,
       anon_1.restaurant_updated_at,
       anon_1.restaurant_image,
       anon_1.restaurant_menu,
       anon_1.opening_time_id,
       anon_1.restaurant_id_1,
       anon_1.restaurant_opening_time_days,
       anon_1.restaurant_opening_time,
       anon_1.restaurant_break_time_days,
       anon_1.restaurant_break_time,
       anon_1.opening_time_created_at,
       anon_1.opening_time_updated_at,
       anon_1.st_distance_sphere_1,
       opening_time_1.opening_time_id              AS opening_time_id_1,
       opening_time_1.restaurant_id                AS restaurant_id_2,
       opening_time_1.restaurant_opening_time_days AS restaurant_opening_time_days_1,
       opening_time_1.restaurant_opening_time      AS restaurant_opening_time_1,
       opening_time_1.restaurant_break_time_days   AS restaurant_break_time_days_1,
       opening_time_1.restaurant_break_time        AS restaurant_break_time_1,
       opening_time_1.opening_time_created_at      AS opening_time_created_at_1,
       opening_time_1.opening_time_updated_at      AS opening_time_updated_at_1,
       restaurant_1.restaurant_id                  AS restaurant_id_3,
       restaurant_1.restaurant_name                AS restaurant_name_1,
       restaurant_1.restaurant_rate                AS restaurant_rate_1,
       restaurant_1.restaurant_category            AS restaurant_category_1,
       restaurant_1.restaurant_count_seats         AS restaurant_count_seats_1,
       restaurant_1.restaurant_x                   AS restaurant_x_1,
       restaurant_1.restaurant_y                   AS restaurant_y_1,
       restaurant_1.restaurant_address             AS restaurant_address_1,
       restaurant_1.restaurant_description         AS restaurant_description_1,
       restaurant_1.restaurant_contact             AS restaurant_contact_1,
       restaurant_1.restaurant_created_at          AS restaurant_created_at_1,
       restaurant_1.restaurant_updated_at          AS restaurant_updated_at_1,
       restaurant_1.restaurant_image               AS restaurant_image_1,
       restaurant_1.restaurant_menu                AS restaurant_menu_1
FROM (SELECT restaurant.restaurant_id                                                    AS restaurant_id,
             restaurant.restaurant_name                                                  AS restaurant_name,
             restaurant.restaurant_rate                                                  AS restaurant_rate,
             restaurant.restaurant_category                                              AS restaurant_category,
             restaurant.restaurant_count_seats                                           AS restaurant_count_seats,
             restaurant.restaurant_x                                                     AS restaurant_x,
             restaurant.restaurant_y                                                     AS restaurant_y,
             restaurant.restaurant_address                                               AS restaurant_address,
             restaurant.restaurant_description                                           AS restaurant_description,
             restaurant.restaurant_contact                                               AS restaurant_contact,
             restaurant.restaurant_created_at                                            AS restaurant_created_at,
             restaurant.restaurant_updated_at                                            AS restaurant_updated_at,
             restaurant.restaurant_image                                                 AS restaurant_image,
             restaurant.restaurant_menu                                                  AS restaurant_menu,
             opening_time.opening_time_id                                                AS opening_time_id,
             opening_time.restaurant_id                                                  AS restaurant_id_1,
             opening_time.restaurant_opening_time_days                                   AS restaurant_opening_time_days,
             opening_time.restaurant_opening_time                                        AS restaurant_opening_time,
             opening_time.restaurant_break_time_days                                     AS restaurant_break_time_days,
             opening_time.restaurant_break_time                                          AS restaurant_break_time,
             opening_time.opening_time_created_at                                        AS opening_time_created_at,
             opening_time.opening_time_updated_at                                        AS opening_time_updated_at,
             st_distance_sphere(point(129.0832792851, 35.2424891575),
                                point(restaurant.restaurant_x, restaurant.restaurant_y)) AS st_distance_sphere_1
      FROM restaurant
               INNER JOIN opening_time ON restaurant.restaurant_id = opening_time.restaurant_id
      WHERE restaurant.restaurant_address LIKE '%%장전동%%'
      ORDER BY st_distance_sphere(point(129.0832792851, 35.2424891575),
                                  point(restaurant.restaurant_x, restaurant.restaurant_y))
      LIMIT 0, 10) AS anon_1
         INNER JOIN opening_time AS opening_time_1 ON anon_1.restaurant_id = opening_time_1.restaurant_id
         INNER JOIN restaurant AS restaurant_1 ON restaurant_1.restaurant_id = anon_1.restaurant_id_1
ORDER BY anon_1.st_distance_sphere_1;

변경 된 ORM의 쿼리는 아래와 같습니다.

SELECT anon_1.restaurant_id,
       anon_1.restaurant_name,
       anon_1.restaurant_rate,
       anon_1.restaurant_category,
       anon_1.restaurant_count_seats,
       anon_1.restaurant_x,
       anon_1.restaurant_y,
       anon_1.restaurant_address,
       anon_1.restaurant_description,
       anon_1.restaurant_contact,
       anon_1.restaurant_created_at,
       anon_1.restaurant_updated_at,
       anon_1.restaurant_image,
       anon_1.restaurant_menu,
       anon_1.st_distance_sphere_1,
       opening_time_1.opening_time_id,
       opening_time_1.restaurant_id AS restaurant_id_1,
       opening_time_1.restaurant_opening_time_days,
       opening_time_1.restaurant_opening_time,
       opening_time_1.restaurant_break_time_days,
       opening_time_1.restaurant_break_time,
       opening_time_1.opening_time_created_at,
       opening_time_1.opening_time_updated_at
FROM (SELECT restaurant.restaurant_id                                                                   AS restaurant_id,
             restaurant.restaurant_name                                                                 AS restaurant_name,
             restaurant.restaurant_rate                                                                 AS restaurant_rate,
             restaurant.restaurant_category                                                             AS restaurant_category,
             restaurant.restaurant_count_seats                                                          AS restaurant_count_seats,
             restaurant.restaurant_x                                                                    AS restaurant_x,
             restaurant.restaurant_y                                                                    AS restaurant_y,
             restaurant.restaurant_address                                                              AS restaurant_address,
             restaurant.restaurant_description                                                          AS restaurant_description,
             restaurant.restaurant_contact                                                              AS restaurant_contact,
             restaurant.restaurant_created_at                                                           AS restaurant_created_at,
             restaurant.restaurant_updated_at                                                           AS restaurant_updated_at,
             restaurant.restaurant_image                                                                AS restaurant_image,
             restaurant.restaurant_menu                                                                 AS restaurant_menu,
             st_distance_sphere(point(129.0832792851, 35.2424891575),
                                point(restaurant.restaurant_x, restaurant.restaurant_y))                AS st_distance_sphere_1
      FROM restaurant
               INNER JOIN opening_time ON restaurant.restaurant_id = opening_time.restaurant_id
      WHERE restaurant.restaurant_address LIKE '%%장전동%%'
      ORDER BY st_distance_sphere(point(129.0832792851, 35.2424891575), point(restaurant.restaurant_x, restaurant.restaurant_y))
      LIMIT 0, 10) AS anon_1
         INNER JOIN opening_time AS opening_time_1 ON anon_1.restaurant_id = opening_time_1.restaurant_id
ORDER BY anon_1.st_distance_sphere_1;
hyeonprojects commented 1 year ago

쿼리 최적화 하면서 배운점

DB가 돌아가는 원리를 생각하면 되는데, 저는 나름 최적화가 잘 되어서 SQL 구문이 짧고 JOIN문이 많이 없을 수록 최적화가 잘 될거라고 생각했습니다.

예를 들면 아래와 같은 코드가 원래 생각한 SQL 쿼리문이였습니다.

SELECT *,
       ST_DISTANCE_SPHERE(POINT(129.0832792851, 35.2424891575), POINT(r.restaurant_x, r.restaurant_y)) as distance
FROM restaurant r
         JOIN opening_time ot on r.restaurant_id = ot.restaurant_id
WHERE r.restaurant_address LIKE '%%장전동%%'
ORDER BY distance
LIMIT 0, 10;

일단 함수형 프로그래밍의 장점과 특성처럼 최적화는 DBMS가 잘할거라는 생각을 가지고 있었죠. (함수형 프로그래밍 논문을 읽어보면 최적화나 작업 효율을 좀 더 컴퓨터에 할당하는 방식입니다.)

그러나 아래의 쿼리가 어느 정도 더 빨랐습니다.

SELECT anon_1.restaurant_id,
       anon_1.restaurant_name,
       anon_1.restaurant_rate,
       anon_1.restaurant_category,
       anon_1.restaurant_count_seats,
       anon_1.restaurant_x,
       anon_1.restaurant_y,
       anon_1.restaurant_address,
       anon_1.restaurant_description,
       anon_1.restaurant_contact,
       anon_1.restaurant_created_at,
       anon_1.restaurant_updated_at,
       anon_1.restaurant_image,
       anon_1.restaurant_menu,
       anon_1.st_distance_sphere_1,
       opening_time_1.opening_time_id,
       opening_time_1.restaurant_id AS restaurant_id_1,
       opening_time_1.restaurant_opening_time_days,
       opening_time_1.restaurant_opening_time,
       opening_time_1.restaurant_break_time_days,
       opening_time_1.restaurant_break_time,
       opening_time_1.opening_time_created_at,
       opening_time_1.opening_time_updated_at
FROM (SELECT restaurant.restaurant_id                                                                   AS restaurant_id,
             restaurant.restaurant_name                                                                 AS restaurant_name,
             restaurant.restaurant_rate                                                                 AS restaurant_rate,
             restaurant.restaurant_category                                                             AS restaurant_category,
             restaurant.restaurant_count_seats                                                          AS restaurant_count_seats,
             restaurant.restaurant_x                                                                    AS restaurant_x,
             restaurant.restaurant_y                                                                    AS restaurant_y,
             restaurant.restaurant_address                                                              AS restaurant_address,
             restaurant.restaurant_description                                                          AS restaurant_description,
             restaurant.restaurant_contact                                                              AS restaurant_contact,
             restaurant.restaurant_created_at                                                           AS restaurant_created_at,
             restaurant.restaurant_updated_at                                                           AS restaurant_updated_at,
             restaurant.restaurant_image                                                                AS restaurant_image,
             restaurant.restaurant_menu                                                                 AS restaurant_menu,
             st_distance_sphere(point(129.0832792851, 35.2424891575),
                                point(restaurant.restaurant_x, restaurant.restaurant_y))                AS st_distance_sphere_1
      FROM restaurant
               INNER JOIN opening_time ON restaurant.restaurant_id = opening_time.restaurant_id
      WHERE restaurant.restaurant_address LIKE '%%장전동%%'
      ORDER BY st_distance_sphere(point(129.0832792851, 35.2424891575), point(restaurant.restaurant_x, restaurant.restaurant_y))
LIMIT 0, 10) AS anon_1
    INNER JOIN opening_time AS opening_time_1 ON anon_1.restaurant_id = opening_time_1.restaurant_id
ORDER BY anon_1.st_distance_sphere_1;

사실 두 차이는 크게 차이가 나지 않습니다. 간단하게 첫번쨰 짧은 쿼리는 약 2s 400ms 쯤이라면 아래 쿼리는 2s 200ms 쯤입니다. 데이터가 많아질수록 더 커지겠죠.

hyeonprojects commented 1 year ago

위 데이터가 왜 느릴까요? 제가 추측하기로 2가지 방향으로 추측이 되는데 간단하게 컴퓨터가 저장소에 돌아가는 원리와 DBMS가 돌아가는 원리를 생각해보면 좋을거 같습니다. (이는 언어 컴파일원리를 생각해보면 쉽게 나옵니다.)

hyeonprojects commented 1 year ago

Screenshot 2023-01-16 at 07 48 24

hyeonprojects commented 1 year ago

허허