MySQL数据库优化的一些笔记_MySQL
bitsCN.com
0. 索引很重要
之前列举记录用了下面的语句。state字段为索引。
SELECT * FROM feed_urls WHERE state='ok' AND feed_url'' LIMIT N,10
当记录数量很大时,有几万之后,这句SQL就很慢了。主要是因为feed_url没有建立索引。后来的解决方法是,把feed_url为空的,设为一个ok以外的state值,就行了。
1. 索引不是万能的
为了计算记录总数,下面的语句会很慢。
mysql> SELECT COUNT(*) FROM feed_urls WHERE state='error';
+----------+
| COUNT(*) |
+----------+
| 30715 |
+----------+
1 row in set (0.14 sec)
mysql> EXPLAIN SELECT COUNT(*) FROM feed_urls WHERE state='error'/G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: feed_urls
type: ref
possible_keys: state,page_index
key: page_index
key_len: 10
ref: const
rows: 25936
Extra: Using where; Using index
1 row in set (0.00 sec)
state为索引,请求用时140ms。遍历了state='error'索引下的每一条记录。
mysql> SELECT state,COUNT(*) FROM feed_urls GROUP BY state;
+----------+----------+
| state | COUNT(*) |
+----------+----------+
| error | 30717 |
| fetching | 8 |
| nofeed | 76461 |
| ok | 74703 |
| queued | 249681 |
+----------+----------+
5 rows in set (0.55 sec)
mysql> EXPLAIN SELECT state,COUNT(*) FROM feed_urls GROUP BY state/G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: feed_urls
type: index
possible_keys: NULL
key: state
key_len: 10
ref: NULL
rows: 431618
Extra: Using index
1 row in set (0.00 sec)
请求用时550ms。遍历了每个state下的每一条记录。
改进方法:
独立一个表用来计数,使用MySQL的Trigger同步计数:
CREATE TRIGGER my_trigger AFTER UPDATE ON feed_urls
FOR EACH ROW BEGIN
IF OLD.state NEW.state THEN
IF NEW.state='ok' THEN
UPDATE feed_stat SET count_feed = count_feed + 1;
END IF;
IF NEW.state IN ('ok', 'error', 'nofeed') THEN
UPDATE feed_stat SET count_access = count_access + 1;
END IF;
END IF;
END
2. 当分页很大时
mysql> SELECT * FROM feed_urls LIMIT 230000, 1/G
*************************** 1. row ***************************
id: 736841f82abb0bc87ccfec7c0fdbd09c30b5a24d
link: http://mappemunde.typepad.com/
title: Tim Peterson
feed_url: NULL
update_time: 2012-05-12 11:01:56
state: queued
http_server: NULL
abstract: NULL
previous_id: ceea30e0ba609b69198c53ce71c44070d69038c5
ref_count: 1
error: NULL
aid: 230001
1 row in set (0.50 sec)
mysql> EXPLAIN SELECT * FROM feed_urls LIMIT 230000, 1/G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: feed_urls
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 431751
Extra:
1 row in set (0.00 sec)
读取一条记录,耗时500ms,因为表记录是变长的,所以MySQL不能算出目标位置,只能每一条记录的数过去。
改进方法:
通过索引定位,数索引比数记录要快,因为索引占用的空间比整条记录小很多。
mysql> SELECT * FROM (SELECT aid FROM feed_urls ORDER BY aid LIMIT 215000, 1) d JOIN feed_urls u ON d.aid=u.aid/G
*************************** 1. row ***************************
aid: 215001
id: 2e4b1a385c8aae40b3ec2af9153805ca446f2029
link: http://ncse.com/
title: NCSE
feed_url: NULL
update_time: 2012-05-12 10:47:15
state: queued
http_server: NULL
abstract: NULL
previous_id: 819a6e3c5edc1624a9b8f171d8d3ae269843785f
ref_count: 3
error: NULL
aid: 215001
1 row in set (0.06 sec)
mysql> EXPLAIN SELECT * FROM (SELECT aid FROM feed_urls ORDER BY aid LIMIT 215000, 1) d JOIN feed_urls u ON d.aid=u.aid/G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table:
type: system
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 1
Extra:
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: u
type: const
possible_keys: aid
key: aid
key_len: 4
ref: const
rows: 1
Extra:
*************************** 3. row ***************************
id: 2
select_type: DERIVED
table: feed_urls
type: index
possible_keys: NULL
key: aid
key_len: 4
ref: NULL
rows: 211001
Extra: Using index
3 rows in set (0.15 sec)
耗时60ms,比之前的方法快了将近10倍。如果LIMIT语句里还有WHERE a=1,应该建立一个(a,aid)的索引。
话说,MySQL好像还是不能直接算出第21500条索引的位置呀,这种方法还是数了索引了,能算出来就直接0ms了。不过这样的效率,对于百万级的,还能应付吧。如果是千万级的或者像我之前在KS创建的一张上亿条记录的表(120G),这种方法就肯定不行了。
经过上述优化,打开最后一页的速度已经很快了(之前需要800ms,现在则为300ms左右)。

膜拜下这Burst.NET最低档次的VPS (30RMB/month)。
root@xiaoxia-pc:~/# ping feed.readself.com -n
PING app.readself.com (184.82.185.32) 56(84) bytes of data.
64 bytes from 184.82.185.32: icmp_req=1 ttl=45 time=161 ms
64 bytes from 184.82.185.32: icmp_req=2 ttl=45 time=161 ms
64 bytes from 184.82.185.32: icmp_req=3 ttl=45 time=161 ms
用同样的方法,优化了搜索引擎的排名算法。即排名过程中选取尽量少的值出来排序,排序后再JOIN一次获取结果的信息。
排序过程如下:
SELECT u.*, count_level(u.id) lv
FROM(
SELECT f.id, f.ref_count, MATCH(i.link,i.title) AGAINST (keywords) score
FROM feed_index i
JOIN feed_urls f ON f.id=i.id
WHERE MATCH(i.link,i.title) AGAINST (keywords)
ORDER BY score*0.5 + score*0.5*(ref_count/max_ref_count_in_result) DESC
LIMIT offset,10
) d JOIN feed_urls u ON u.id = d.id
目前处理10万记录的全文索引数据,MySQL还是可以满足的,就是不知道上百万之后,还能不能撑下去。撑不下去就依赖第三方的工具了,例如Sphinx
3. SELECT里的函数
给FeedDB增加了层次的显示。因为本人太懒,所以没有给数据库表增加一个记录深度的字段。所以,直接写了一个MySQL的自定义函数 count_level,用来统计通过parent_id一直找到顶层经过的路径长度(Level)。
CREATE DEFINER=`feeddb_rw`@`%` FUNCTION `count_level`(fid char(40)) RETURNS int(11)
BEGIN
SET @levels = 0;
SET @found = false;
WHILE NOT @found DO
SELECT previous_id INTO @prev_id FROM feed_urls WHERE id=fid;
IF @prev_id is null OR @prev_id = '' THEN
SET @found = true;
ELSE
SET @levels = @levels + 1;
SET fid = @prev_id;
END IF;
END WHILE;
IF @prev_id is null THEN
RETURN null;
END IF;
RETURN @levels;
END
在网页显示的时候用了类似下面的SQL语句。
mysql> SELECT u.*, count_level(u.id) FROM feed_urls u ORDER BY ref_count DESC LIMIT 12000,1/G
*************************** 1. row ***************************
id: e42f44b04dabbb9789ccb4709278e881c54c28a3
link: http://tetellita.blogspot.com/
title: le hamburger et le croissant
feed_url: http://www.blogger.com/feeds/7360650/posts/default
update_time: 2012-05-15 14:50:53
state: ok
http_server: GSE
abstract: Lepekmezest un épais sirop bordeaux obtenu par réduction dumoût de raisin, une sorte de mélasse de raisin, en somme. Légèrement acidulé, il apporte du pep's aux yaourts et nappe avec bonheur les
previous_id: 129cabd96e7099a53b78c7ddeff98658351082e9
ref_count: 9
error: NULL
aid: 174262
count_level(u.id): 8
1 row in set (4.10 sec)
好吧,悲剧了!4100ms。一定对12000个条目都算了一次count_level,然后再进行排序。所以才用上了4秒那么漫长的时间!!!
改进方法:
先SELECT LIMIT,再在派生的临时表里,计算count_level。
mysql> SELECT u.*, count_level(u.id) FROM (
SELECT id FROM feed_urls ORDER BY ref_count DESC LIMIT 27521,1
) d JOIN feed_urls u ON u.id=d.id/G
*************************** 1. row ***************************
id: 61df288dda131ffd6125452d20ad0648f38abafd
link: http://mynokiamobile.org/
title: My Nokia Mobile
feed_url: http://mynokiamobile.org/feed/
update_time: 2012-05-14 14:06:57
state: ok
http_server: Apache/2.2.19 (Unix) mod_ssl/2.2.19 OpenSSL/1.0.0-fips mod_auth_passthrough/2.1 mod_bwlimited/1.4 FrontPage/5.0.2.2635
abstract: ArchivesSelect MonthMay 2012April 2012March 2012February 2012January 2012December 2011November 2011October 2011September 2011August 2011July 2011June 2011May 2011April 2011March 2011February 2011Janua
previous_id: f37af92bb89c08f6d4b69e72eab05d8ab1e2aca4
ref_count: 5
error: NULL
aid: 154996
count_level(u.id): 8
1 row in set (0.09 sec)
如此,优化之后效果好很多了!但是还可以继续优化,例如建立一个字段存储Level的值应该是最好的办法了。
初次了解MySQL一些工作机制,欢迎一起探讨!
参考文献:
http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
http://www.mysqlperformanceblog.com/2006/09/01/order-by-limit-performance-optimization/
bitsCN.com
핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Pinduoduo 소프트웨어는 좋은 제품을 많이 제공하고 언제 어디서나 구입할 수 있으며 각 제품의 품질은 엄격하게 통제되고 모든 제품은 정품이며 우대 쇼핑 할인이 많아 누구나 온라인 쇼핑을 할 수 있습니다. 온라인으로 로그인하려면 휴대폰 번호를 입력하고, 온라인으로 여러 배송 주소와 연락처 정보를 추가하고, 다양한 카테고리의 제품 섹션을 언제든지 확인하고 구매하고 주문하세요. 집을 떠나지 않고도 편리함을 경험할 수 있습니다. 온라인 쇼핑 서비스를 이용하면 구매한 상품을 포함한 모든 구매 기록을 볼 수 있으며, 수십 개의 쇼핑 빨간 봉투와 쿠폰을 무료로 받을 수 있습니다. 이제 편집자가 자세한 온라인 정보를 제공합니다. Pinduoduo 사용자는 구매한 제품 기록을 볼 수 있습니다. 1. 휴대폰을 열고 핀둬둬 아이콘을 클릭하세요.

Linux에서 명령 기록을 보는 방법 Linux에서는 이전에 실행된 모든 명령 목록을 보려면 History 명령을 사용합니다. 이것은 매우 간단한 구문을 가지고 있습니다:historyhistory 명령과 쌍을 이루는 일부 옵션은 다음과 같습니다. 옵션 설명 -c는 현재 세션에 대한 명령 기록을 지웁니다. -w는 명령 기록을 파일에 기록합니다. -r은 기록 파일에서 명령 기록을 다시 로드합니다. n 최근 명령의 출력 수 제한 Linux 터미널에서 이전에 실행된 모든 명령 목록을 보려면 간단히 History 명령을 실행하십시오. 명령 기록을 보는 것 외에도 명령 기록을 관리하고 이전에 실행한 명령에 대한 수정을 수행할 수도 있습니다. 명령 기록을 검색하거나 기록을 완전히 삭제할 수도 있습니다.

iPhone의 통화 녹음은 종종 과소평가되며 iPhone의 가장 중요한 기능 중 하나입니다. 단순하기 때문에 이 기능은 매우 중요하며 장치에서 걸거나 받은 통화에 대한 중요한 통찰력을 제공할 수 있습니다. 업무 목적이든 법적 절차이든 통화 기록에 액세스하는 기능은 매우 중요할 수 있습니다. 간단히 말해서 통화 기록은 전화를 걸거나 받을 때마다 iPhone에 생성된 항목을 의미합니다. 이러한 로그에는 연락처 이름(또는 연락처로 저장되지 않은 경우 번호), 타임스탬프, 통화 시간, 통화 상태(전화 걸기, 부재중 또는 응답하지 않음)를 포함한 주요 정보가 포함됩니다. 이는 귀하의 의사소통 이력에 대한 간결한 기록입니다. 통화 기록에는 iPhone에 저장된 통화 기록 스트립이 포함됩니다.

iPhone을 사용하면 건강 앱에 약을 추가하여 매일 복용하는 약, 비타민, 보충제를 추적하고 관리할 수 있습니다. 그러면 장치에서 알림을 받을 때 복용했거나 건너뛴 약을 기록할 수 있습니다. 약을 기록한 후에는 건강을 추적하는 데 도움이 되도록 약을 복용하거나 건너뛴 빈도를 확인할 수 있습니다. 이번 포스팅에서는 iPhone의 건강 앱에서 선택한 약물의 로그 기록을 보는 방법을 안내하겠습니다. 건강 앱에서 약물 기록 기록을 보는 방법에 대한 간단한 가이드: 건강 앱> 찾아보기> 약품> 약품> 약품 선택> 옵션&a로 이동하세요.

Hibernate 쿼리 성능을 최적화하기 위한 팁은 다음과 같습니다: 지연 로딩을 사용하여 컬렉션 및 관련 개체 로드를 연기하고, 일괄 처리를 사용하여 업데이트, 삭제 또는 삽입 작업을 결합하여 HQL 외부 연결을 사용하여 자주 쿼리되는 개체를 메모리에 저장합니다. 엔터티 및 관련 엔터티를 검색하고, SELECTN+1 쿼리 모드를 피하기 위해 쿼리 매개변수를 최적화합니다. 커서를 사용하여 블록의 대규모 데이터를 검색합니다.

C# 개발 제안: 로깅 및 모니터링 시스템 요약: 소프트웨어 개발 프로세스에서 로깅 및 모니터링 시스템은 중요한 도구입니다. 이 문서에서는 C# 개발에서 로깅 및 모니터링 시스템의 역할과 구현 제안을 소개합니다. 소개: 로깅 및 모니터링은 대규모 소프트웨어 개발 프로젝트에 필수적인 도구입니다. 이를 통해 프로그램의 실행 상태를 실시간으로 이해하고 문제를 신속하게 발견하고 해결할 수 있습니다. 이 문서에서는 C# 개발에서 로깅 및 모니터링 시스템을 사용하여 소프트웨어 품질과 개발 효율성을 향상시키는 방법에 대해 설명합니다. 로깅 시스템의 역할

Java 개발 프로젝트를 기록하고 모니터링하는 방법 1. 배경 소개 인터넷의 급속한 발전으로 인해 점점 더 많은 회사에서 Java를 개발하고 다양한 유형의 애플리케이션을 구축하기 시작했습니다. 개발 과정에서 로깅과 모니터링은 무시할 수 없는 중요한 연결고리입니다. 로깅 및 모니터링을 통해 개발자는 적시에 문제를 발견하고 해결하여 애플리케이션의 안정성과 보안을 보장할 수 있습니다. 2. 로깅의 중요성 1. 문제 추적: 애플리케이션 오류가 발생할 경우 로깅을 통해 문제를 빠르게 찾을 수 있습니다.

데이터베이스 최적화를 통해 Python 웹 사이트의 액세스 속도를 향상시키는 방법은 무엇입니까? 요약 Python 웹 사이트를 구축할 때 데이터베이스는 중요한 구성 요소입니다. 데이터베이스 액세스 속도가 느리면 웹 사이트의 성능과 사용자 경험에 직접적인 영향을 미칩니다. 이 문서에서는 일부 샘플 코드와 함께 Python 웹 사이트의 액세스 속도를 향상시키기 위해 데이터베이스를 최적화하는 몇 가지 방법에 대해 설명합니다. 소개 대부분의 Python 웹사이트에서 데이터베이스는 데이터를 저장하고 검색하는 핵심 부분입니다. 최적화되지 않으면 데이터베이스가 성능 병목 현상을 일으킬 수 있습니다. 책
