X-Original-To: pgsql-performance-postgresql.org@localhost.postgresql.org Received: from localhost (av.hub.org [200.46.204.144]) by svr1.postgresql.org (Postfix) with ESMTP id 1985CD9FA6 for ; Tue, 4 Oct 2005 05:45:14 -0300 (ADT) Received: from svr1.postgresql.org ([200.46.204.71]) by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024) with ESMTP id 23350-09 for ; Tue, 4 Oct 2005 08:45:07 +0000 (GMT) Received: from boutiquenumerique.com (boutiquenumerique.com [82.67.9.10]) by svr1.postgresql.org (Postfix) with ESMTP id 08422D72AA for ; Tue, 4 Oct 2005 05:45:07 -0300 (ADT) Received: (qmail 32426 invoked from network); 4 Oct 2005 10:46:02 +0200 Received: from unknown (HELO localhost) (boutiquenumerique-lists@192.168.0.4) by boutiquenumerique.com with SMTP; 4 Oct 2005 10:46:02 +0200 Date: Tue, 04 Oct 2005 10:45:06 +0200 To: Joe Subject: Re: Comparative performance Cc: pgsql-performance@postgresql.org References: <6BCB9D8A16AC4241919521715F4D8BCE92E6D6@algol.sollentuna.se> <433BDB0B.8010002@freedomcircle.net> <433BE1A0.5000807@freedomcircle.net> <4341E328.2060305@freedomcircle.net> From: PFC Organization: =?utf-8?Q?La_Boutique_Num=C3=A9rique?= Content-Type: text/plain; format=flowed; delsp=yes; charset=utf-8 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID: In-Reply-To: <4341E328.2060305@freedomcircle.net> User-Agent: Opera M2/8.0 (Linux, build 1095) X-Virus-Scanned: by amavisd-new at hub.org X-Spam-Status: No, hits=0.006 required=5 tests=[AWL=0.006] X-Spam-Level: X-Archive-Number: 200510/39 X-Sequence-Number: 14807 It's more understandable if the table names are in front of the column names : SELECT relationship.topic_id1, relationship.topic_id2, topic.topic_name, topic.categ_id, topic.list_name, topic.title, topic.url, topic.page_type, relationship.rel_type, entry_type.inverse_id, relationship.description AS rel_descrip, relationship.created, relationship.updated FROM relationship, topic, entry_type WHERE ((relationship.topic_id1 = topic.topic_id AND relationship.topic_id2 = 1252) OR (relationship.topic_id2 = topic.topic_id and relationship.topic_id1 = 1252)) AND relationship.rel_type = entry_type.type_id AND entry_type.class_id = 2 ORDER BY rel_type, list_name; I see a few problems in your schema. - topic_id1 and topic_id2 play the same role, there is no constraint to determine which is which, hence it is possible to define the same relation twice. - as you search on two columns with OR, you need UNION to use indexes. - lack of indexes - I don't understand why the planner doesn't pick up hash joins... - if you use a version before 8, type mismatch will prevent use of the indexes. I'd suggest rewriting the query like this : SELECT topic.*, foo.* FROM topic, (SELECT topic_id2 as fetch_id, topic_id1, topic_id2, rel_type, description as rel_descrip, created, updated FROM relationship WHERE rel_type IN (SELECT type_id FROM entry_type WHERE class_id = 2) AND topic_id1 = 1252 UNION SELECT topic_id1 as fetch_id, topic_id1, topic_id2, rel_type, description as rel_descrip, created, updated FROM relationship WHERE rel_type IN (SELECT type_id FROM entry_type WHERE class_id = 2) AND topic_id2 = 1252) AS foo WHERE topic.topic_id = foo.fetch_id CREATE INDEX'es ON entry_type( class_id ) relationship( topic_id1, rel_type, topic_id2 ) which becomes your new PRIMARY KEY relationship( topic_id2, rel_type, topic_id1 ) > Of course, this doesn't explain how MySQL manages to execute the query > in about 9 msec. The only minor differences in the schema are: > entry_type.title and rel_title are char(32) in MySQL, > entry_type.class_id is a tinyint, and topic.categ_id, page_type and > dark_ind are also tinyints. MySQL also doesn't have the REFERENCES. Can you post the result from MySQL EXPLAIN ? You might be interested in the following code. Just replace mysql_ by pg_, it's quite useful. $global_queries_log = array(); function _getmicrotime() { list($u,$s) = explode(' ',microtime()); return $u+$s; } /* Formats query, with given arguments, escaping all strings as needed. db_quote_query( 'UPDATE junk SET a=%s WHERE b=%s', array( 1,"po'po" ) ) => UPDATE junk SET a='1 WHERE b='po\'po' */ function db_quote_query( $sql, $params=false ) { // if no params, send query raw if( !$params ) return $sql; // quote params foreach( $params as $key => $val ) { if( is_array( $val )) $val = implode( ',', $val ); $params[$key] = "'".mysql_real_escape_string( $val )."'"; } return vsprintf( $sql, $params ); } /* Formats query, with given arguments, escaping all strings as needed. Runs query, logging its execution time. Returns the query, or dies with error. */ function db_query( $sql, $params=false ) { // it's already a query if( is_resource( $sql )) return $sql; $sql = db_quote_query( $sql, $params ); $t = _getmicrotime(); $r = mysql_query( $sql ); if( !$r ) { echo "
Erreur MySQL :
".mysql_error()."

Requ􏻪te :
".$sql."

Traceback :
";
		foreach( debug_backtrace() as $t ) xdump( $t );
		echo "
"; die(); } global $global_queries_log; $global_queries_log[] = array( _getmicrotime()-$t, $sql ); return $r; } At the end of your page, display the contents of $global_queries_log.