2

4GB RAM, 2CPUs, 60GB SSD 특성을 가진 VPS에서 Prestashop 1.6 powered e-shop을 실행 중입니다. 현재 내 가게에는 약 20000 개의 제품이 있고 mysql 쿼리가 오래 실행되기 때문에 사이트 로딩에 문제가 있습니다. 그리고 htop을 실행하여 프로세스를 분석 할 때 mysql은 두 CPU의 100 %를 소비합니다. MySQL을 Prestashop 1.6 용으로 최적화

-------- Performance Metrics ------------------------------------------------- 
[--] Up for: 1h 29m 9s (241K q [45.109 qps], 319 conn, TX: 318M, RX: 126M) 
[--] Reads/Writes: 78%/22% 
[--] Total buffers: 192.0M global + 2.7M per thread (151 max threads) 
[OK] Maximum possible memory usage: 597.8M (15% of installed RAM) 
[OK] Slow queries: 0% (8/241K) 
[OK] Highest usage of available connections: 2% (4/151) 
[OK] Key buffer size/total MyISAM indexes: 16.0M/44.9M 
[OK] Key buffer hit rate: 99.6% (36M cached/133K reads) 
[OK] Query cache efficiency: 49.6% (101K cached/205K selects) 
[!!] Query cache prunes per day: 1386761 
[OK] Sorts requiring temporary tables: 0% (1 temp sorts/7K sorts) 
[!!] Joins performed without indexes: 78 
[OK] Temporary tables created on disk: 8% (846 on disk/9K total) 
[OK] Thread cache hit rate: 98% (4 created/319 connections) 
[!!] Table cache hit rate: 10% (340 open/3K opened) 
[OK] Open file limit used: 62% (643/1K) 
[OK] Table locks acquired immediately: 100% (239K immediate/239K locks) 

-------- Recommendations ----------------------------------------------------- 
General recommendations: 
    Add skip-innodb to MySQL configuration to disable InnoDB 
    MySQL started within last 24 hours - recommendations may be inaccurate 
    Enable the slow query log to troubleshoot bad queries 
    Adjust your join queries to always utilize indexes 
    Increase table_cache gradually to avoid file descriptor limits 
Variables to adjust: 
    query_cache_size (> 16M) 
    join_buffer_size (> 128.0K, or always use indexes with joins) 
    table_cache (> 400) 

어떤 최적화 방법을 제안하십시오 :이 mysqltuner의 출력이다.

편집 :

느린 쿼리 출력 로그가 here입니다.

+0

기본적으로 무료로 전문 튜닝 도움말을 찾고 계시지 만 어디에서 최적화를 시작해야할지 모르십니까? –

+0

느린 쿼리 로그를 얻고 성능을 저하시키는 실제 범인 SQL 쿼리를 게시하는 방법은 어떻습니까? 통계량이 많지 않고 서술 된 쿼리와 알려진 인덱스를 보지 못하는 것이 실제로 상황이 질식하는 곳일 수 있습니다. 나는 느린 쿼리와 0 % 퍼센트가 일치한다면 동의 할 수 없다. INDEXES = 78이없는 JOINS를 확인하십시오. – DRapp

+0

@DRapp는 느린 쿼리 로그 http://pastie.org/9664946 – torayeff

답변

0

다음은 로그에서 다른 로그를 조사하는 두 번째 쿼리입니다. 이를 돕기 위해 서브 쿼리를 없애기 위해 약간 재구성하여 INNER JOIN으로 바 꾸었습니다. 또한 다른 사람들이 귀하의 테이블을 알지 못하도록 돕기 위해 항상 level_depth, nleft, nright의 출처를 알기 위해 필드 참조를 table.column 또는 alias.column으로 한정하십시오. 그것은 인덱스에 도움이 될 수 있습니다.

인덱스의 경우 테이블 당 다음과 같습니다.

ps_category, index ON(active, id_category, id_lang, nleft, nright, level_depth) 
ps_category_lang, index ON(id_category, id_shop, id_lang) 
ps_category_shop, index ON(id_category, id_shop) 
ps_category_group, index ON(id_category, id_group) 
ps_lang, index ON(id_lang, active) 

약간

SELECT 
     c.id_parent, 
     c.id_category, 
     cl.name, 
     cl.description, 
     cl.link_rewrite 
    FROM 
     ps_category c 
     INNER JOIN ps_category_lang cl 
      ON c.id_category = cl.id_category 
      AND cl.id_shop = 1 
      AND cl.id_lang = 2 
     INNER JOIN ps_category_shop cs 
      ON c.id_category = cs.id_category 
      AND cs.id_shop = 1 
     INNER JOIN ps_category_group psg 
      ON c.id_category = psg.id_category 
      AND psg.id_group = 1 
    WHERE 
     ( c.active = 1 
     OR c.id_category = 2) 
     AND c.id_category != 1 
     AND level_depth <= 7 
     AND nleft >= 350 AND nright <= 351 
    ORDER BY 
     level_depth ASC, 
     cs.position ASC; 

세 번째 쿼리 쿼리

재 작성. 이 경우 특정 키 요소 중 일부가 맨 위로 이동되므로 키 인덱스에도 해당 항목이 있고 나머지는 where 절 (주로 가독성 조정)에 대한 "특정"요소를 보는 데 도움이됩니다. 인덱스 장점)

SELECT 
     c.id_category, 
     cl.name, 
     cl.link_rewrite 
    FROM 
     ps_category c 
     LEFT JOIN ps_category_lang cl 
      ON c.id_category = cl.id_category 
      AND cl.id_shop = 1 
     INNER JOIN ps_category_shop category_shop 
      ON c.id_category = category_shop.id_category 
      AND category_shop.id_shop = 1 
    WHERE 
      c.active = 1 
     AND cl.id_lang = 2 
     AND c.nleft between 2 and 350 
     AND c.nright between 351 and 625 
     AND c.level_depth > 1 
    ORDER BY 
     c.level_depth ASC; 

당신은 당신이 정말로 원하는 것을 확인해야 다음 질의 ... 당신은 언어 테이블에 왼쪽 합류,하지만 추가 "l.active = 1"WHERE 절에 사실 INNER JOIN으로 바꿀 것입니다. 당신이 진정으로 원하는 경우 내가 희망이 인덱스 및 쿼리의 샘플 설명/가독성이 로그를 개선하는 데 도움이 여기

SELECT 
     l.id_lang, 
     c.link_rewrite 
    FROM 
     ps_category_lang AS c 
     LEFT JOIN ps_lang AS l 
      ON c.id_lang = l.id_lang 
      AND l.active = 1 
    WHERE 
     c.id_category = 324 

조정과 같은 조인 부분으로 l.active 이동, LEFT-가입하세요. 다른 사람들과 여전히 문제가 있다면 필요에 따라 게시하십시오. SLOW 로그 보고서 첫 번째 쿼리에서

먼저 쿼리에 대한

개정은, 당신이 특정 제품 가게에서 일을 찾고 있습니다 나타납니다. 그러나 제품 카테고리로 쿼리를 시작하고 제품에 왼쪽으로 합류 한 다음 제품 상점에 연결합니다. 이러한 제품은 궁극적으로 특정 카테고리와 관련이 있으므로 어디서나 내부 결합을 만듭니다.I는 (id_shop 활성, 가시성 id_product, id_category_default) 단일 인덱스, 예를 들어 다수의 필드 인덱스를 생성로서

SELECT 
     p.*, 
     ps.*, 
     stock.out_of_stock, 
     IFNULL(stock.quantity, 0) as quantity, 
     MAX(pas.id_product_attribute) id_product_attribute, 
     pas.minimal_quantity AS product_attribute_minimal_quantity, 
     pl.description, 
     pl.description_short, 
     pl.available_now, 
     pl.available_later, 
     pl.link_rewrite, 
     pl.meta_description, 
     pl.meta_keywords, 
     pl.meta_title, 
     pl.name, 
     MAX(image_shop.id_image) id_image, 
     il.legend, 
     m.name AS manufacturer_name, 
     cl.name AS category_default, 
     DATEDIFF(ps.`date_add`, DATE_SUB(NOW(),INTERVAL 20 DAY)) > 0 AS new, 
     ps.price AS orderprice 
    FROM 
     (select @thisLanguage := 1) sqlvars, 
     ps_product_shop ps 
     INNER JOIN ps_product p 
      ON ps.id_product = p.id_product 

      INNER JOIN ps_category_product cp 
       ON id_product = cp.id_product 
       AND cp.id_category = 2 

      LEFT JOIN ps_product_attribute pa 
       ON p.id_product = pa.id_product 
       LEFT JOIN ps_product_attribute_shop pas 
        ON pa.id_product_attribute = pas.id_product_attribute 
        AND ps.id_shop = pas.id_shop 
        AND pas.default_on = 1 

      LEFT JOIN ps_stock_available stock 
       ON p.id_product = stock.id_product 
       AND ps.id_shop = stock.id_shop 
       AND stock.id_shop_group = 0 
       AND stock.id_product_attribute = IFNULL(pas.id_product_attribute, 0) 

      LEFT JOIN ps_product_lang pl 
       ON p.id_product = pl.id_product 
       AND ps.id_shop = pl.id_shop 
       AND pl.id_lang = @thisLanguage 

      LEFT JOIN ps_image i 
       ON p.id_product = i.id_product 
       LEFT JOIN ps_image_shop image_shop 
        ON i.id_image = image_shop.id_image 
        AND ps.id_shop = image_shop.id_shop 
        AND image_shop.cover = 1 
        LEFT JOIN ps_image_lang il 
        ON image_shop.id_image = il.id_image 
        AND il.id_lang = @thisLanguage 

      LEFT JOIN ps_manufacturer m 
       ON p.id_manufacturer = m.id_manufacturer 

     LEFT JOIN ps_category_lang cl 
      ON ps.id_category_default = cl.id_category 
      AND cl.id_shop = ps.id_shop 
      AND cl.id_lang = @thisLanguage 
    WHERE 
      ps.id_shop = 1 
     AND ps.active = 1 
     AND ps.visibility IN ("both", "catalog") 
    GROUP BY 
     ps.id_product 
    ORDER BY 
     cp.position ASC 
    LIMIT 
     0,8; 

ON ps_product_shop에 단일 인덱스 것이다

아래와 같이 I 다소 재구성 할 :

CREATE INDEX act_id_lang ON ps_category (활성, id_category, id_lang, nleft, nright, level_depth);

은 단순한 인덱스 이름을 ... 모든 테이블에 ... 모든 키와 함께 제공하므로 쿼리에서 효과적입니다.

+0

두 번째 들어 쿼리 Query_time : 0.001116. 왜 그것을 최적화해야합니까? 첫 번째 쿼리는 길다. Query_time : 11.635315 – torayeff

+0

@torayeff, 첫 번째 쿼리를 다시 살펴 보겠다.하지만 인덱스 자체는 도움이 될 것이며 작성된 쿼리는 나를 보여 주며 어떤 인덱스가 전체를 돕는 데 가장 도움이되는지 식별 할 수 있도록 도와 준다. 판. 나는 곧 첫 번째 쿼리로 돌아갈 것이다. – DRapp

+0

인덱스는 이미 해당 열 – torayeff

0

더 오랜 사용 시간이 지난 후에는 mysqltuner를 사용해야합니다. 다음 메시지가 제거되어야합니다. MySQL이 지난 24 시간 내에 시작되었습니다. - 권장 사항이 정확하지 않을 수 있습니다.