php.de

Zurück   php.de > Webentwicklung > Datenbanken

Datenbanken SQL und Co

Antwort
 
LinkBack (1) Themen-Optionen Thema bewerten
Alt 26.08.2008, 17:51  
Neuer Benutzer
 
Registriert seit: 26.08.2008
Beiträge: 3
__abcde__ befindet sich auf einem aufstrebenden Ast
Standard Query optimieren

Hallo,

ich bräuchte ein bisschen Hilfe beim Optimieren von folgender Abfrage:
Code:
SELECT distinct(forum_topic.id) AS distinct_1
FROM forum_topic, forum_post
WHERE forum_post.author_id = 3134
AND forum_post.topic_id = forum_topic.id
AND forum_topic.forum_id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
ORDER BY forum_topic.last_post_id DESC  LIMIT 0, 30;
Wenn ich das ausführe, dauert es 30+ Sekunden (forum_post hat ~ 1.5 Millionen und forum_topic fast 200000 Einträge). Ein EXPLAIN gibt mir das hier aus:
Code:
mysql> explain SELECT distinct(forum_topic.id) AS distinct_1  FROM forum_topic, forum_post  WHERE forum_post.author_id = 3134 AND forum_post.topic_id = forum_topic.id AND forum_topic.forum_id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) ORDER BY forum_topic.last_post_id DESC  LIMIT 0, 30;
+----+-------------+-------------+--------+-------------------------------------------------------------------------+----------------------+---------+--------------------------------------+------+---------------------------------+
| id | select_type | table       | type   | possible_keys                                                           | key                  | key_len | ref                                  | rows | Extra                           |
+----+-------------+-------------+--------+-------------------------------------------------------------------------+----------------------+---------+--------------------------------------+------+---------------------------------+
|  1 | SIMPLE      | forum_post  | ref    | forum_post_author_id,forum_post_topic_id,viewtopic,forum_post_egosearch | forum_post_egosearch | 4       | const                                | 3076 | Using temporary; Using filesort | 
|  1 | SIMPLE      | forum_topic | eq_ref | PRIMARY,viewforum                                                       | PRIMARY              | 4       | ubuntu_de_inyoka.forum_post.topic_id |    1 | Using where                     | 
+----+-------------+-------------+--------+-------------------------------------------------------------------------+----------------------+---------+--------------------------------------+------+---------------------------------+
2 rows in set (0.00 sec)
Ich nehme an, dass das "Using temporary; Using filesort" dafür verantwortlich ist, dass es so lange dauert.
Das sind die Indizes, die die forum_post-Tabelle hat:
Code:
mysql> show indexes from forum_post;
+------------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table      | Non_unique | Key_name             | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+------------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| forum_post |          0 | PRIMARY              |            1 | id          | A         |     1640642 |     NULL | NULL   |      | BTREE      | NULL    | 
| forum_post |          1 | forum_post_author_id |            1 | author_id   | A         |      205080 |     NULL | NULL   |      | BTREE      | NULL    | 
| forum_post |          1 | forum_post_topic_id  |            1 | topic_id    | A         |      273440 |     NULL | NULL   |      | BTREE      | NULL    | 
| forum_post |          1 | viewtopic            |            1 | topic_id    | A         |      546880 |     NULL | NULL   |      | BTREE      | NULL    | 
| forum_post |          1 | viewtopic            |            2 | position    | A         |     1640642 |     NULL | NULL   |      | BTREE      | NULL    | 
| forum_post |          1 | forum_post_pub_date  |            1 | pub_date    | A         |     1640642 |     NULL | NULL   |      | BTREE      | NULL    | 
| forum_post |          1 | forum_post_egosearch |            1 | author_id   | A         |        6459 |     NULL | NULL   |      | BTREE      | NULL    | 
| forum_post |          1 | forum_post_egosearch |            2 | id          | A         |     1640642 |     NULL | NULL   |      | BTREE      | NULL    | 
+------------+------------+----------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
8 rows in set (1.04 sec)
Kann mir jemand helfen, die Abfrage annehmbar schnell zu machen?

Danke schonmal im Vorraus,

__abcde__
__abcde__ ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 26.08.2008, 18:09  
Erfahrener Benutzer
 
Benutzerbild von David
 
Registriert seit: 05.09.2007
Beiträge: 5.044
David wird schon bald berühmt werden
Standard

Erstmal ein kleiner Tipp, was zum Beispiel mich motivieren könnte, damit rumzuspielen:
Direkt verwertbare Daten angeben.
Also etwas, das man nicht erst noch umschreiben muss, um sich eine Testumgebung zu basteln. In diesem Fall wäre das die Ausgabe von SHOW CREATE TABLE und eine überschaubare Menge Testdatensätze als Dumpfile oder in der Form INSERT INTO ...(...) VALUES (....)
David ist offline   Mit Zitat antworten
Alt 26.08.2008, 18:47  
Moderator und Wett-König
 
Benutzerbild von dr.e.
 
Registriert seit: 21.05.2008
Beiträge: 3.654
PHP-Kenntnisse:
Fortgeschritten
dr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblick
dr.e. eine Nachricht über Skype™ schicken
Standard

Zitat:
Ich nehme an, dass das "Using temporary; Using filesort" dafür verantwortlich ist, dass es so lange dauert.
Exakt, das ist eine sehr teure Operation, da hier massiv File-IO entsteht.

Zitat:
Kann mir jemand helfen, die Abfrage annehmbar schnell zu machen?
Ich würde versuchen, die einschränkenden Argumente optimaler zu strukturieren. In deinem Fall wäre das, den JOIN

Code:
AND forum_post.topic_id = forum_topic.id
als erste Bedingung zu formulieren, dann sparst du dir das durchsuchen von zig Beiträgen in der Tabelle forum_post. Grundsärtlich solltest du versuchen, bei JOINs nur gegen Integer-Indizes zu joinen, alles andere wird verdammt langsam.

Was ich grad noch gesehen habe: evtl. ist auch

Code:
AND forum_topic.forum_id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
die einschränkendere Klausel.
__________________
Viele Grüße,
Dr.E.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Think about software design before you start to write code!
2. Discuss and review it together with experts!
3. Choose good tools (-> Adventure PHP Framework (APF))!
4. Write clean and reusable software only!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dr.e. ist offline   Mit Zitat antworten
Alt 26.08.2008, 19:40  
Neuer Benutzer
 
Registriert seit: 26.08.2008
Beiträge: 3
__abcde__ befindet sich auf einem aufstrebenden Ast
Standard

@David: Hier (kann man in dem Forum keine Dateien anhängen?) ein Dump mit ein paar Testeinträgen (die unwichtigen Spalten habe ich rausgekürzt):
Code:
--
-- Table structure for table `forum_post`
--

DROP TABLE IF EXISTS `forum_post`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `forum_post` (
  `id` int(11) NOT NULL auto_increment,
  `author_id` int(11) NOT NULL,
  `topic_id` int(11) NOT NULL,
  `text` longtext collate utf8_unicode_ci,
  PRIMARY KEY  (`id`),
  KEY `forum_post_author_id` (`author_id`),
  KEY `forum_post_topic_id` (`topic_id`),
  KEY `forum_post_egosearch` (`author_id`,`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
SET character_set_client = @saved_cs_client;

--
-- Dumping data for table `forum_post`
--

LOCK TABLES `forum_post` WRITE;
/*!40000 ALTER TABLE `forum_post` DISABLE KEYS */;
INSERT INTO `forum_post` VALUES (1,2,1,'Ad. Et quisque pellentesque penatibus;\n\nRhoncus ridiculus vulputate non nonummy malesuada lectus nisl nascetur proin nibh gravida est laoreet felis donec eros?\n\nmorbi metus odio dolor natoque mus est pellentesque penatibus dictum elit turpis ullamcorper ligula ullamcorper habitant est eu curabitur bibendum.'),(2,3,1,'Amet tincidunt sit sociis sodales facilisi porta aliquet dapibus diam pellentesque penatibus litora bibendum quisque. interdum rutrum sodales hac hendrerit aliquet litora aliquet dignissim convallis mauris et urna nunc laoreet libero;\n\nId sed posuere potenti pellentesque penatibus aptent lorem luctus dapibus diam sit sociis lacinia feugiat habitasse tincidunt tincidunt netus. tellus quam dui vulputate sit sociis nunc orci commodo tortor quisque sit sociis ligula quis eleifend elementum inceptos curae urna! Condimentum leo suscipit quisque nec curae nascetur quis imperdiet platea.'),(3,1,1,'eros rhoncus ridiculus lorem luctus curabitur accumsan sem aliquet aenean enim at auctor massa risus dis tempor tempus elit venenatis eu quis. Eleifend elementum facilisi platea eros curabitur ligula commodo?'),(4,2,1,'Cras per rutrum consectetuer consequat maecenas lectus eros quisque at auctor dictumst tortor amet lacinia lacinia?'),(5,2,2,'Porttitor pharetra blandit pretium condimentum placerat bibendum magnis dictumst venenatis aptent proin torquent accumsan? Rutrum rutrum;'),(6,3,2,'Tellus eget dolor et ligula nullam mauris?'),(7,1,3,'Maecenas ante duis magna maecenas sem eu pellentesque penatibus fames faucibus urna duis aenean porttitor elit id curabitur; quis egestas rhoncus ridiculus accumsan sodales posuere potenti vel porttitor commodo nulla fringilla duis sit sociis curae duis purus amet tristique velit; '),(8,2,4,'Torquent duis nascetur! Eleifend elementum condimentum iaculis natoque facilisis etiam vel quis eu amet montes augue magna. Congue senectus fames faucibus varius condimentum feugiat duis curabitur vel? Curae rhoncus ridiculus.'),(9,1,5,' Pretium etiam aliquet placerat urna accumsan ac metus?');
/*!40000 ALTER TABLE `forum_post` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `forum_topic`
--

DROP TABLE IF EXISTS `forum_topic`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `forum_topic` (
  `id` int(11) NOT NULL auto_increment,
  `forum_id` int(11) NOT NULL,
  `title` varchar(100) collate utf8_unicode_ci NOT NULL,
  `author_id` int(11) NOT NULL,
  `first_post_id` int(11) default NULL,
  `last_post_id` int(11) default NULL,
  PRIMARY KEY  (`id`),
  KEY `forum_topic_first_post_id` (`first_post_id`),
  KEY `forum_topic_last_post_id` (`last_post_id`),
  CONSTRAINT `first_post_id_refs_id_7ced225d` FOREIGN KEY (`first_post_id`) REFERENCES `forum_post` (`id`),
  CONSTRAINT `last_post_id_refs_id_7ced225d` FOREIGN KEY (`last_post_id`) REFERENCES `forum_post` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
SET character_set_client = @saved_cs_client;

--
-- Dumping data for table `forum_topic`
--

LOCK TABLES `forum_topic` WRITE;
/*!40000 ALTER TABLE `forum_topic` DISABLE KEYS */;
INSERT INTO `forum_topic` VALUES (1,1,'Interdum porta pellentesquepenatibus!',2,1,4),(2,1,'Laoreet nam?',2,5,6),(3,1,'Egestas id!',1,7,9);
/*!40000 ALTER TABLE `forum_topic` ENABLE KEYS */;
UNLOCK TABLES;

--
-- Table structure for table `portal_user`
--

DROP TABLE IF EXISTS `portal_user`;
SET @saved_cs_client     = @@character_set_client;
SET character_set_client = utf8;
CREATE TABLE `portal_user` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(30) collate utf8_unicode_ci NOT NULL,
  PRIMARY KEY  (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
SET character_set_client = @saved_cs_client;

--
-- Dumping data for table `portal_user`
--

LOCK TABLES `portal_user` WRITE;
/*!40000 ALTER TABLE `portal_user` DISABLE KEYS */;
INSERT INTO `portal_user` VALUES (1,'dolor'),(2,'ipsum'),(3,'lorem');
/*!40000 ALTER TABLE `portal_user` ENABLE KEYS */;
UNLOCK TABLES;
Zitat:
In deinem Fall wäre das, den JOIN [...] als erste Bedingung zu formulieren, dann sparst du dir das durchsuchen von zig Beiträgen in der Tabelle forum_post.
hab ich geändert, hat allerdings nichts bewirkt :/
Zitat:
Was ich grad noch gesehen habe: evtl. ist auch [...] die einschränkendere Klausel.
Auch wenn ich das entferne, bleibt es so langsam.
__abcde__ ist offline   Mit Zitat antworten
Alt 27.08.2008, 11:12  
Erfahrener Benutzer
 
Benutzerbild von David
 
Registriert seit: 05.09.2007
Beiträge: 5.044
David wird schon bald berühmt werden
Standard

Code:
alter table forum_post add index xyz (topic_id,author_id)
Code:
Explain SELECT
  forum_topic.id as tid
FROM
  forum_topic
WHERE
  EXISTS(
    SELECT
      topic_id
    FROM
      forum_post
    WHERE
      author_id = 3134
      AND tid=topic_id
  )  
ORDER BY
  forum_topic.last_post_id DESC
LIMIT
  0, 30
Zitat:
id,select_type,table,type,possible_keys,key,key_le n,ref,rows,Extra
1,PRIMARY,forum_topic,index,,forum_topic_last_post _id,5,,3,Using where; Using index
2,DEPENDENT SUBQUERY,forum_post,ref,xyz,xyz,8,func,const,1,Using where; Using index
David ist offline   Mit Zitat antworten
Alt 27.08.2008, 13:08  
Moderator und Wett-König
 
Benutzerbild von dr.e.
 
Registriert seit: 21.05.2008
Beiträge: 3.654
PHP-Kenntnisse:
Fortgeschritten
dr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblickdr.e. ist ein Lichtblick
dr.e. eine Nachricht über Skype™ schicken
Standard

@David: sehr schön! Ich hätte als nächstes auch auf Index-Selektivität getippt.
__________________
Viele Grüße,
Dr.E.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1. Think about software design before you start to write code!
2. Discuss and review it together with experts!
3. Choose good tools (-> Adventure PHP Framework (APF))!
4. Write clean and reusable software only!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dr.e. ist offline   Mit Zitat antworten
Alt 27.08.2008, 14:49  
Erfahrener Benutzer
 
Benutzerbild von David
 
Registriert seit: 05.09.2007
Beiträge: 5.044
David wird schon bald berühmt werden
Standard

Trotz LINQ hat es sich als notwendig herausgestellt, an meinen SQL Fähigkeiten zu arbeiten
David ist offline   Mit Zitat antworten
Alt 27.08.2008, 23:57  
Neuer Benutzer
 
Registriert seit: 26.08.2008
Beiträge: 3
__abcde__ befindet sich auf einem aufstrebenden Ast
Standard

@David: Danke, dadurch geht das Query sehr schnell (0.2 Sekunden). Wenn ich allerdings das
Code:
AND forum_topic.forum_id IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
wieder dazu tue wird es wieder langsam (10 Sekunden) und er benutzt für forum_topic nicht mehr den Index:
Code:
+----+--------------------+-------------+-------+-----------------------------------------------------------------------------------+--------------------------+---------+------------+--------+--------------------------+
| id | select_type        | table       | type  | possible_keys                                                                     | key                      | key_len | ref        | rows   | Extra                    |
+----+--------------------+-------------+-------+-----------------------------------------------------------------------------------+--------------------------+---------+------------+--------+--------------------------+
|  1 | PRIMARY            | forum_topic | index | viewforum                                                                         | forum_topic_last_post_id | 5       | NULL       | 188200 | Using where              | 
|  2 | DEPENDENT SUBQUERY | forum_post  | ref   | forum_post_author_id,forum_post_topic_id,viewtopic,forum_post_egosearch,egosearch | egosearch                | 8       | func,const |      1 | Using where; Using index | 
+----+--------------------+-------------+-------+-----------------------------------------------------------------------------------+--------------------------+---------+------------+--------+--------------------------+
2 rows in set (0.00 sec)
ich habe ein bisschen mit den Indizes gespielt (z.B. forum_id, last_post_id), aber das hat leider nicht geholfen :/
Was muss ich machen, dass er dafür auch einen Index benutzen kann?

Geändert von __abcde__ (27.08.2008 um 23:59 Uhr).
__abcde__ ist offline   Mit Zitat antworten
Alt 28.08.2008, 10:44  
Erfahrener Benutzer
 
Benutzerbild von David
 
Registriert seit: 05.09.2007
Beiträge: 5.044
David wird schon bald berühmt werden
Standard

Zitat:
Zitat von __abcde__ Beitrag anzeigen
ich habe ein bisschen mit den Indizes gespielt (z.B. forum_id, last_post_id), aber das hat leider nicht geholfen :/
Das hätte ich jetzt auch gedacht, hmmm.
David ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

LinkBacks (?)
LinkBack to this Thread: http://www.php.de/datenbanken/46995-query-optimieren.html
Erstellt von For Type Datum
Neue Antwort im Thema 'Query optimieren' - spamavert.com This thread Refback 02.09.2008 23:29

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
NS Query Problem GSJLink Datenbanken 0 07.09.2007 18:04
Variablen in Query automatisch escapen Maho88 PHP Tipps 2007 10 31.07.2007 08:42
SQL Query Builder gesucht MaMo-Net Beitragsarchiv 10 08.05.2007 21:42
Mysql Server Einstellunen Optimieren pchero Datenbanken 3 01.05.2007 19:50
PHP/MySQL: Query wird nicht ausgeführt Zergling-new Tutorials 5 09.05.2006 23:16
query und ' speichern? flflfl PHP Tipps 2006 2 14.04.2006 18:21
Insert Into Query optimieren bendigo Datenbanken 4 02.03.2006 18:39
query r�cksetzen? Promaetheus PHP Tipps 2007 15 01.12.2005 13:53
[Erledigt] Hartnäckiges SQL Query... Datenbanken 1 05.10.2005 18:23
Query, was aus einer Tabelle mehrere Summen rausholt Datenbanken 3 14.09.2005 16:45
PEAR::DB Optimierung für Query und Arrayfüllung? PHP Tipps 2005 7 17.05.2005 20:47
mysql query fehler Datenbanken 6 19.01.2005 23:44
select query durch if anweisungen splitten Datenbanken 6 06.09.2004 13:46
immer mysql_select_db vor query wenn man pconnect benutzt robo47 PHP Tipps 2004 8 03.09.2004 14:56
[Erledigt] Query läuft nicht Datenbanken 6 13.08.2004 21:13

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
query optimieren, sql query optimieren, mysql optimieren using filesort, query optimierung using where, query update um id zu optimieren, query: set character_set_client = @saved_cs_client;

Alle Zeitangaben in WEZ +2. Es ist jetzt 02:17 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum