Mam tabelę Joomla z tysiącami wierszy treści (około 3 milionów). Mam problem przy przepisywaniu zapytań do bazy danych tak szybko, jak to możliwe podczas wysyłania zapytań do tabel.Złożona kwerenda MySQL wciąż używająca filesort chociaż indeksy istnieją
Oto mój pełny zapytania:
SELECT cc.title AS category, a.id, a.title, a.alias, a.title_alias, a.introtext, a.fulltext, a.sectionid, a.state, a.catid, a.created, a.created_by, a.created_by_alias, a.modified, a.modified_by, a.checked_out, a.checked_out_time, a.publish_up, a.publish_down, a.attribs, a.hits, a.images, a.urls, a.ordering, a.metakey, a.metadesc, a.access, CASE WHEN CHAR_LENGTH(a.alias) THEN CONCAT_WS(":", a.id, a.alias) ELSE a.id END AS slug, CASE WHEN CHAR_LENGTH(cc.alias) THEN CONCAT_WS(":", cc.id, cc.alias) ELSE cc.id END AS catslug, CHAR_LENGTH(a.`fulltext`) AS readmore, u.name AS author, u.usertype, g.name AS groups, u.email AS author_email
FROM j15_content AS a
LEFT JOIN j15_categories AS cc
ON a.catid = cc.id
LEFT JOIN j15_users AS u
ON u.id = a.created_by
LEFT JOIN j15_groups AS g
ON a.access = g.id
WHERE 1
AND a.access <= 0
AND a.catid = 108
AND a.state = 1
AND (publish_up = '0000-00-00 00:00:00' OR publish_up <= '2012-02-08 00:16:26')
AND (publish_down = '0000-00-00 00:00:00' OR publish_down >= '2012-02-08 00:16:26')
ORDER BY a.title, a.created DESC
LIMIT 0, 10
Oto wynik od wyjaśniania:
+----+-------------+-------+--------+-------------------------------------------------------+-----------+---------+---------------------------+---------+-----------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------------------------------------------+-----------+---------+---------------------------+---------+-----------------------------+
| 1 | SIMPLE | a | ref | idx_access,idx_state,idx_catid,idx_access_state_catid | idx_catid | 4 | const | 3108187 | Using where; Using filesort |
| 1 | SIMPLE | cc | const | PRIMARY | PRIMARY | 4 | const | 1 | |
| 1 | SIMPLE | u | eq_ref | PRIMARY | PRIMARY | 4 | database.a.created_by | 1 | |
| 1 | SIMPLE | g | eq_ref | PRIMARY | PRIMARY | 1 | database.a.access | 1 | |
+----+-------------+-------+--------+-------------------------------------------------------+-----------+---------+---------------------------+---------+-----------------------------+
i pokazać co istnieją indeksy, pokaż indeks z j15_content:
+-------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+-------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| j15_content | 0 | PRIMARY | 1 | id | A | 3228356 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_section | 1 | sectionid | A | 2 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_access | 1 | access | A | 1 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_checkout | 1 | checked_out | A | 2 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_state | 1 | state | A | 2 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_catid | 1 | catid | A | 6 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_createdby | 1 | created_by | A | 1 | NULL | NULL | | BTREE | |
| j15_content | 1 | title | 1 | title | A | 201772 | 4 | NULL | | BTREE | |
| j15_content | 1 | idx_access_state_catid | 1 | access | A | 1 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_access_state_catid | 2 | state | A | 2 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_access_state_catid | 3 | catid | A | 7 | NULL | NULL | | BTREE | |
| j15_content | 1 | idx_title_created | 1 | title | A | 3228356 | 8 | NULL | | BTREE | |
| j15_content | 1 | idx_title_created | 2 | created | A | 3228356 | NULL | NULL | | BTREE | |
+-------------+------------+------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
Jak widać, z bazy danych pobieranych jest kilka danych. Teraz testowałem, upraszczając zapytanie, że prawdziwy problem leży w klauzuli ORDER BY. Bez zamawiania wyników, zapytanie jest bardzo czuły, tutaj jest wyjaśnienie:
+----+-------------+-------+--------+-------------------------------------------------------+-----------+---------+---------------------------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-------------------------------------------------------+-----------+---------+---------------------------+---------+-------------+
| 1 | SIMPLE | a | ref | idx_access,idx_state,idx_catid,idx_access_state_catid | idx_catid | 4 | const | 3108187 | Using where |
| 1 | SIMPLE | cc | const | PRIMARY | PRIMARY | 4 | const | 1 | |
| 1 | SIMPLE | u | eq_ref | PRIMARY | PRIMARY | 4 | database.a.created_by | 1 | |
| 1 | SIMPLE | g | eq_ref | PRIMARY | PRIMARY | 1 | database.a.access | 1 | |
+----+-------------+-------+--------+-------------------------------------------------------+-----------+---------+---------------------------+---------+-------------+
Jak widać jest to śmiertelne filesort że zabija serwer. Przy tak wielu wierszach robię co w mojej mocy, aby zoptymalizować wszystko za pomocą indeksów, ale coś jest z tym nie w porządku. Wszelkie dane wejściowe będą bardzo mile widziane.
spróbował wykorzystać FORCE INDEX bezskutecznie:
explain SELECT cc.title AS category, a.id, a.title, a.alias, a.title_alias, a.introtext, a.fulltext, a.sectionid, a.state, a.catid, a.created, a.created_by, a.created_by_alias, a.modified, a.modified_by, a.checked_out, a.checked_out_time, a.publish_up, a.publish_down, a.attribs, a.hits, a.images, a.urls, a.ordering, a.metakey, a.metadesc, a.access, CASE WHEN CHAR_LENGTH(a.alias) THEN CONCAT_WS(":", a.id, a.alias) ELSE a.id END AS slug, CASE WHEN CHAR_LENGTH(cc.alias) THEN CONCAT_WS(":", cc.id, cc.alias) ELSE cc.id END AS catslug, CHAR_LENGTH(a.`fulltext`) AS readmore, u.name AS author, u.usertype, g.name AS groups, u.email AS author_email
-> FROM bak_content AS a
-> FORCE INDEX (idx_title_created)
-> LEFT JOIN bak_categories AS cc
-> ON a.catid = cc.id
-> LEFT JOIN bak_users AS u
-> ON u.id = a.created_by
-> LEFT JOIN bak_groups AS g
-> ON a.access = g.id
-> WHERE 1
-> AND a.access <= 0
-> AND a.catid = 108
-> AND a.state = 1
-> AND (publish_up = '0000-00-00 00:00:00' OR publish_up <= '2012-02-08
-> AND (publish_down = '0000-00-00 00:00:00' OR publish_down >= '2012-0
-> ORDER BY a.title, a.created DESC
-> LIMIT 0, 10;
Produkuje:
+----+-------------+-------+--------+---------------+---------+---------+-------
| id | select_type | table | type | possible_keys | key | key_len | ref
+----+-------------+-------+--------+---------------+---------+---------+-------
| 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL
| 1 | SIMPLE | cc | const | PRIMARY | PRIMARY | 4 | const
| 1 | SIMPLE | u | eq_ref | PRIMARY | PRIMARY | 4 | database
| 1 | SIMPLE | g | eq_ref | PRIMARY | PRIMARY | 1 | database
+----+-------------+-------+--------+---------------+---------+---------+-------
Spróbowałbym jednego z tych indeksów: '(stan, catid, dostęp)' lub '(stan, catid, publish_up)' lub '(stan, catid, publish_down)' –
Jeśli nie używasz 'LIMIT' wiele wierszy jest zwracanych? –
Można również spróbować wymusić użycie indeksu 'idx_title_created'. –