ปัญหาประสิทธิภาพการทำงานของ MySQL โดยใช้คอลัมน์วันที่จัดทำดัชนี


15

ฉันพยายามที่จะแก้ปัญหาต่อไปนี้เป็นเวลาประมาณหนึ่งชั่วโมงในขณะนี้และยังไม่ได้รับเพิ่มเติมด้วย

โอเคฉันมีโต๊ะ (MyISAM):

+---------+-------------+------+-----+-------------------+----------------+
| Field   | Type        | Null | Key | Default           | Extra          |
+---------+-------------+------+-----+-------------------+----------------+
| id      | int(11)     | NO   | PRI | NULL              | auto_increment |
| http    | smallint(3) | YES  | MUL | 200               |                |
| elapsed | float(6,3)  | NO   |     | NULL              |                |
| cached  | tinyint(1)  | YES  |     | NULL              |                |
| ip      | int(11)     | NO   |     | NULL              |                |
| date    | timestamp   | NO   | MUL | CURRENT_TIMESTAMP |                |
+---------+-------------+------+-----+-------------------+----------------+

กรุณาอย่ารังเกียจดัชนีฉันได้ลองเล่นเพื่อหาทางแก้ไข ตอนนี้นี่คือคำถามของฉัน

SELECT http,
COUNT( http )  AS count 
FROM reqs
WHERE DATE(date) >= cast(date_sub(date(NOW()),interval 24 hour) as datetime)
GROUP BY http
ORDER BY count;

ตารางกำลังจัดเก็บข้อมูลเกี่ยวกับคำขอทางเว็บที่เข้ามาดังนั้นจึงเป็นฐานข้อมูลที่ค่อนข้างใหญ่

+-----------+
| count(id) |
+-----------+
|    782412 |
+-----------+

โปรดทราบว่าไม่มีวิธีที่ดีกว่าในการตั้งค่าคีย์หลักเนื่องจากคอลัมน์idจะเป็นตัวระบุเฉพาะที่ฉันมี แบบสอบถามดังกล่าวข้างต้นใช้เวลาประมาณ 0.6-1.6 วินาทีในการเรียกใช้

ดัชนีใดจะฉลาด? ฉันคิดว่าวันที่จัดทำดัชนีจะให้ความสำคัญเชิงหัวใจที่ "แย่" และดังนั้น MySQL จะไม่ใช้มัน httpเป็นตัวเลือกที่ไม่ดีเนื่องจากมีค่าที่เป็นไปได้ที่แตกต่างกันประมาณ 20 ค่าเท่านั้น

ขอบคุณสำหรับความช่วยเหลือของคุณ!

อัปเดต 1ฉันได้เพิ่มดัชนีใน(http, วันที่)ตามที่แนะนำใน ypercube:

mysql> CREATE INDEX httpDate ON reqs (http, date);

และใช้การค้นหาของเขา แต่มันก็ทำได้ไม่ดีเท่ากัน ดัชนีเพิ่ม:

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| reqs  |          0 | PRIMARY  |            1 | id          | A         |      798869 |     NULL | NULL   |      | BTREE      |         |
| reqs  |          1 | httpDate |            1 | http        | A         |          19 |     NULL | NULL   | YES  | BTREE      |         |
| reqs  |          1 | httpDate |            2 | date        | A         |       99858 |     NULL | NULL   |      | BTREE      |         |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+

และอธิบาย

+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
| id | select_type        | table | type  | possible_keys | key      | key_len | ref  | rows  | Extra                                                     |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+
|  1 | PRIMARY            | r     | range | NULL          | httpDate | 3       | NULL |    20 | Using index for group-by; Using temporary; Using filesort |
|  2 | DEPENDENT SUBQUERY | ri    | ref   | httpDate      | httpDate | 3       | func | 41768 | Using where; Using index                                  |
+----+--------------------+-------+-------+---------------+----------+---------+------+-------+-----------------------------------------------------------+

รุ่นเซิร์ฟเวอร์ MySQL:

mysql> SHOW VARIABLES LIKE "%version%";
+-------------------------+---------------------+
| Variable_name           | Value               |
+-------------------------+---------------------+
| protocol_version        | 10                  |
| version                 | 5.1.73              |
| version_comment         | Source distribution |
| version_compile_machine | x86_64              |
| version_compile_os      | redhat-linux-gnu    |
+-------------------------+---------------------+
5 rows in set (0.00 sec)

คุณสามารถเพิ่มเวอร์ชัน mysql และเอ็นจิ้นของตารางได้อย่างไร (myisam หรือ innodb)
ypercubeᵀᴹ

MyISAM และ 5.1.73 - รายละเอียดทั้งหมดตอนนี้ในโพสต์
Robin Heller

ฉันเกรงว่ามันอาจจะเกี่ยวข้องกับhttpคอลัมน์ที่ไม่มีค่า ฉันจะตรวจสอบพรุ่งนี้ถ้าฉันหาเวลา
ypercubeᵀᴹ

ฉันเกรงว่าอาจเกี่ยวข้องกับคอลัมน์ http ที่เป็นโมฆะ ฉันจะตรวจสอบพรุ่งนี้ถ้าฉันหาเวลา คุณสามารถทดสอบโดยการสร้างตารางที่เหมือนกัน (ยกเว้นด้วยhttp NOT NULL) และคัดลอกข้อมูลทั้งหมดไปยังมัน (ยกเว้นแถวที่มี http NULL แน่นอน)
ypercubeᵀᴹ

การเปลี่ยนเป็น NOT NULL (ซึ่งเป็นไปได้ทั้งหมดฉันไม่ได้คิดอะไรมากเมื่อสร้างตาราง) เพิ่มประสิทธิภาพเป็นประมาณ 1 ~ 1.6s สำหรับการค้นหา (แบบสอบถามของฉัน) ขอบคุณสำหรับความพยายามของคุณจนถึงขณะนี้
Robin Heller

คำตอบ:


10

ฉันมีสามข้อเสนอแนะ

SUGGESTION # 1: เขียนแบบสอบถามใหม่

คุณควรเขียนแบบสอบถามดังต่อไปนี้

SELECT http,
COUNT( http )  AS count 
FROM reqs
WHERE date >= ( DATE(NOW() - INTERVAL 1 DAY) + INTERVAL 0 SECOND )
GROUP BY http
ORDER BY count;

หรือ

SELECT * FROM
(
    SELECT http,
    COUNT( http )  AS count 
    FROM reqs
    WHERE date >= ( DATE(NOW() - INTERVAL 1 DAY) + INTERVAL 0 SECOND )
    GROUP BY http
) A ORDER BY count;

ที่ไม่ควรมีฟังก์ชั่นทั้งสองด้านของเครื่องหมายเท่ากับ การมีวันที่ทางด้านซ้ายของเครื่องหมายเท่ากับทำให้ง่ายขึ้นสำหรับ Query Optimizer เพื่อใช้ดัชนีกับมัน

SUGGESTION # 2: ดัชนีการสนับสนุน

ฉันจะแนะนำดัชนีอื่นด้วย

ALTER TABLE reqs ADD INDEX date_http_ndx (date,http); -- not (http,date) 

ฉันแนะนำลำดับคอลัมน์นี้เพราะdateทุกรายการจะอยู่ติดกันในดัชนี จากนั้นแบบสอบถามเพียงแค่เก็บค่าโดยไม่ข้ามช่องว่างในhttphttp

SUGGESTION # 3: บัฟเฟอร์ที่ใหญ่กว่า (เลือกได้)

MyISAM ใช้การแคชดัชนีเท่านั้น เนื่องจากแบบสอบถามไม่ควรแตะ.MYDไฟล์คุณควรใช้ MyISAM Key Buffer ที่ใหญ่ขึ้นเล็กน้อย

หากต้องการตั้งเป็น 256M

SET @newsize = 1024 * 1024 * 256;
SET GLOBAL key_buffer_size = @newsize;

จากนั้นตั้งค่าเป็น my.cnf

[mysqld]
key_buffer_size = 256M

ไม่จำเป็นต้องทำการรีสตาร์ท MySQL

ให้มันลอง !!!


ฉันลองคำถามที่คุณให้ฉัน # 1 ทำได้ดีพอ ๆ กับข้อเสนอแนะอื่น ๆ หรือของฉันคนที่สองนั้นแย่กว่าจริง ๆ สิ่งเดียวกันสำหรับดัชนีการสนับสนุน - ทำให้ประสิทธิภาพลดลงประมาณ 75 เปอร์เซ็นต์ ฉันจะลองใช้บัฟเฟอร์คีย์ที่ใหญ่ขึ้นในตอนนี้ขอบคุณอีกครั้ง!
Robin Heller

ฉันยอมรับคำตอบของคุณแม้ว่ามันจะไม่สามารถแก้ปัญหาได้ แต่ก็มีบัฟเฟอร์ที่ใหญ่กว่า แต่ก็ทำงานได้ดีกว่า ปิดนี่เป็นทางออกที่ดีที่สุดของทั้งหมดที่ได้รับ ขอขอบคุณ!
Robin Heller

เพื่อให้ข้อเสนอแนะ # 2 ทำงานได้อาจจำเป็นต้องเพิ่ม "USE INDEX" หรือ "FORCE INDEX" ในแบบสอบถามอย่างน้อยนั่นคือสิ่งที่ฉันต้องทำเพื่อเพิ่มความเร็วในแบบสอบถามของฉันหลังจากสร้างดัชนีเช่นนั้น
Johano Fierra

-2

เปลี่ยนประเภทคอลัมน์วันที่ของคุณเป็นจำนวนเต็ม เก็บวันที่เป็นวันที่ Unix เป็นจำนวนเต็ม Timestamp มีขนาดใหญ่กว่า int คุณจะได้รับบางอย่างจากที่


2
คุณล้อเล่นใช่ไหม ทั้งสองINTและTIMESTAMPต้องการ 4 ไบต์
ypercubeᵀᴹ

2
อย่าพูดถึงว่าคุณสูญเสียฟังก์ชันวันที่และเวลาทั้งหมดเมื่อคุณเก็บวันที่หรือเวลาเป็นจำนวนเต็ม
ypercubeᵀᴹ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.