⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perform.sgml

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 SGML
📖 第 1 页 / 共 3 页
字号:
<!--$PostgreSQL: pgsql/doc/src/sgml/perform.sgml,v 1.54 2005/11/04 23:14:00 petere Exp $--> <chapter id="performance-tips">  <title>Performance Tips</title>  <indexterm zone="performance-tips">   <primary>performance</primary>  </indexterm>  <para>   Query performance can be affected by many things. Some of these can    be manipulated by the user, while others are fundamental to the underlying   design of the system.  This chapter provides some hints about understanding   and tuning <productname>PostgreSQL</productname> performance.  </para>  <sect1 id="using-explain">   <title>Using <command>EXPLAIN</command></title>   <indexterm zone="using-explain">    <primary>EXPLAIN</primary>   </indexterm>   <indexterm zone="using-explain">    <primary>query plan</primary>   </indexterm>   <para>    <productname>PostgreSQL</productname> devises a <firstterm>query    plan</firstterm> for each query it is given.  Choosing the right    plan to match the query structure and the properties of the data    is absolutely critical for good performance, so the system includes    a complex <firstterm>planner</> that tries to select good plans.    You can use the    <xref linkend="sql-explain" endterm="sql-explain-title"> command    to see what query plan the planner creates for any query.    Plan-reading is an art that deserves an extensive tutorial, which    this is not; but here is some basic information.   </para>   <para>    The structure of a query plan is a tree of <firstterm>plan nodes</>.    Nodes at the bottom level are table scan nodes: they return raw rows    from a table.  There are different types of scan nodes for different    table access methods: sequential scans, index scans, and bitmap index    scans.  If the query requires joining, aggregation, sorting, or other    operations on the raw rows, then there will be additional nodes    <quote>atop</> the scan nodes to perform these operations.  Again,    there is usually more than one possible way to do these operations,    so different node types can appear here too.  The output    of <command>EXPLAIN</command> has one line for each node in the plan    tree, showing the basic node type plus the cost estimates that the planner    made for the execution of that plan node.  The first line (topmost node)    has the estimated total execution cost for the plan; it is this number    that the planner seeks to minimize.   </para>   <para>    Here is a trivial example, just to show what the output looks like.    <footnote>     <para>      Examples in this section are drawn from the regression test database      after doing a <command>VACUUM ANALYZE</>, using 8.1 development sources.      You should be able to get similar results if you try the examples yourself,      but your estimated costs and row counts will probably vary slightly      because <command>ANALYZE</>'s statistics are random samples rather      than being exact.     </para>    </footnote><programlisting>EXPLAIN SELECT * FROM tenk1;                         QUERY PLAN------------------------------------------------------------- Seq Scan on tenk1  (cost=0.00..458.00 rows=10000 width=244)</programlisting>   </para>   <para>    The numbers that are quoted by <command>EXPLAIN</command> are:    <itemizedlist>     <listitem>      <para>       Estimated start-up cost (Time expended before output scan can start,       e.g., time to do the sorting in a sort node.)      </para>     </listitem>     <listitem>      <para>       Estimated total cost (If all rows were to be retrieved, which they may       not be: for example, a query with a <literal>LIMIT</> clause will stop       short of paying the total cost of the <literal>Limit</> plan node's       input node.)      </para>     </listitem>     <listitem>      <para>       Estimated number of rows output by this plan node (Again, only if       executed to completion.)      </para>     </listitem>     <listitem>      <para>       Estimated average width (in bytes) of rows output by this plan       node      </para>     </listitem>    </itemizedlist>   </para>   <para>    The costs are measured in units of disk page fetches; that is, 1.0    equals one sequential disk page read, by definition.  (CPU effort    estimates are made too; they are converted into disk-page units using some    fairly arbitrary fudge factors. If you want to experiment with these    factors, see the list of run-time configuration parameters in    <xref linkend="runtime-config-query-constants">.)   </para>   <para>    It's important to note that the cost of an upper-level node includes    the cost of all its child nodes.  It's also important to realize that    the cost only reflects things that the planner cares about.    In particular, the cost does not consider the time spent transmitting    result rows to the client, which could be an important    factor in the true elapsed time; but the planner ignores it because    it cannot change it by altering the plan.  (Every correct plan will    output the same row set, we trust.)   </para>   <para>    Rows output is a little tricky because it is <emphasis>not</emphasis> the    number of rows processed or scanned by the plan node.  It is usually less,    reflecting the estimated selectivity of any <literal>WHERE</>-clause    conditions that are being     applied at the node.  Ideally the top-level rows estimate will    approximate the number of rows actually returned, updated, or deleted    by the query.   </para>   <para>    Returning to our example:<programlisting>EXPLAIN SELECT * FROM tenk1;                         QUERY PLAN------------------------------------------------------------- Seq Scan on tenk1  (cost=0.00..458.00 rows=10000 width=244)</programlisting>   </para>   <para>    This is about as straightforward as it gets.  If you do<programlisting>SELECT relpages, reltuples FROM pg_class WHERE relname = 'tenk1';</programlisting>    you will find out that <classname>tenk1</classname> has 358 disk    pages and 10000 rows.  So the cost is estimated at 358 page    reads, defined as costing 1.0 apiece, plus 10000 * <xref    linkend="guc-cpu-tuple-cost"> which is    typically 0.01 (try <command>SHOW cpu_tuple_cost</command>).   </para>   <para>    Now let's modify the query to add a <literal>WHERE</> condition:<programlisting>EXPLAIN SELECT * FROM tenk1 WHERE unique1 &lt; 7000;                         QUERY PLAN------------------------------------------------------------ Seq Scan on tenk1  (cost=0.00..483.00 rows=7033 width=244)   Filter: (unique1 &lt; 7000)</programlisting>    Notice that the <command>EXPLAIN</> output shows the <literal>WHERE</>    clause being applied as a <quote>filter</> condition; this means that    the plan node checks the condition for each row it scans, and outputs    only the ones that pass the condition.    The estimate of output rows has gone down because of the <literal>WHERE</>    clause.    However, the scan will still have to visit all 10000 rows, so the cost    hasn't decreased; in fact it has gone up a bit to reflect the extra CPU    time spent checking the <literal>WHERE</> condition.   </para>   <para>    The actual number of rows this query would select is 7000, but the rows    estimate is only approximate.  If you try to duplicate this experiment,    you will probably get a slightly different estimate; moreover, it will    change after each <command>ANALYZE</command> command, because the    statistics produced by <command>ANALYZE</command> are taken from a    randomized sample of the table.   </para>   <para>    Now, let's make the condition more restrictive:<programlisting>EXPLAIN SELECT * FROM tenk1 WHERE unique1 &lt; 100;                                  QUERY PLAN------------------------------------------------------------------------------ Bitmap Heap Scan on tenk1  (cost=2.37..232.35 rows=106 width=244)   Recheck Cond: (unique1 &lt; 100)   ->  Bitmap Index Scan on tenk1_unique1  (cost=0.00..2.37 rows=106 width=0)         Index Cond: (unique1 &lt; 100)</programlisting>    Here the planner has decided to use a two-step plan: the bottom plan    node visits an index to find the locations of rows matching the index    condition, and then the upper plan node actually fetches those rows    from the table itself.  Fetching the rows separately is much more    expensive than sequentially reading them, but because not all the pages    of the table have to be visited, this is still cheaper than a sequential    scan.  (The reason for using two levels of plan is that the upper plan    node sorts the row locations identified by the index into physical order    before reading them, so as to minimize the costs of the separate fetches.    The <quote>bitmap</> mentioned in the node names is the mechanism that    does the sorting.)   </para>   <para>    If the <literal>WHERE</> condition is selective enough, the planner may    switch to a <quote>simple</> index scan plan:<programlisting>EXPLAIN SELECT * FROM tenk1 WHERE unique1 &lt; 3;                                  QUERY PLAN------------------------------------------------------------------------------ Index Scan using tenk1_unique1 on tenk1  (cost=0.00..10.00 rows=2 width=244)   Index Cond: (unique1 &lt; 3)</programlisting>    In this case the table rows are fetched in index order, which makes them    even more expensive to read, but there are so few that the extra cost    of sorting the row locations is not worth it.  You'll most often see    this plan type for queries that fetch just a single row, and for queries    that request an <literal>ORDER BY</> condition that matches the index    order.   </para>   <para>    Add another condition to the <literal>WHERE</> clause:<programlisting>EXPLAIN SELECT * FROM tenk1 WHERE unique1 &lt; 3 AND stringu1 = 'xxx';                                  QUERY PLAN------------------------------------------------------------------------------ Index Scan using tenk1_unique1 on tenk1  (cost=0.00..10.01 rows=1 width=244)   Index Cond: (unique1 &lt; 3)   Filter: (stringu1 = 'xxx'::name)</programlisting>    The added condition <literal>stringu1 = 'xxx'</literal> reduces the    output-rows estimate, but not the cost because we still have to visit the    same set of rows.  Notice that the <literal>stringu1</> clause    cannot be applied as an index condition (since this index is only on    the <literal>unique1</> column).  Instead it is applied as a filter on    the rows retrieved by the index.  Thus the cost has actually gone up    a little bit to reflect this extra checking.   </para>   <para>    If there are indexes on several columns used in <literal>WHERE</>, the    planner might choose to use an AND or OR combination of the indexes:<programlisting>EXPLAIN SELECT * FROM tenk1 WHERE unique1 &lt; 100 AND unique2 &gt; 9000;                                     QUERY PLAN------------------------------------------------------------------------------------- Bitmap Heap Scan on tenk1  (cost=11.27..49.11 rows=11 width=244)   Recheck Cond: ((unique1 &lt; 100) AND (unique2 &gt; 9000))   -&gt;  BitmapAnd  (cost=11.27..11.27 rows=11 width=0)         -&gt;  Bitmap Index Scan on tenk1_unique1  (cost=0.00..2.37 rows=106 width=0)               Index Cond: (unique1 &lt; 100)         -&gt;  Bitmap Index Scan on tenk1_unique2  (cost=0.00..8.65 rows=1042 width=0)               Index Cond: (unique2 &gt; 9000)</programlisting>    But this requires visiting both indexes, so it's not necessarily a win    compared to using just one index and treating the other condition as    a filter.  If you vary the ranges involved you'll see the plan change    accordingly.   </para>   <para>    Let's try joining two tables, using the columns we have been discussing:<programlisting>EXPLAIN SELECT * FROM tenk1 t1, tenk2 t2 WHERE t1.unique1 &lt; 100 AND t1.unique2 = t2.unique2;                                      QUERY PLAN-------------------------------------------------------------------------------------- Nested Loop  (cost=2.37..553.11 rows=106 width=488)   -&gt;  Bitmap Heap Scan on tenk1 t1  (cost=2.37..232.35 rows=106 width=244)         Recheck Cond: (unique1 &lt; 100)         -&gt;  Bitmap Index Scan on tenk1_unique1  (cost=0.00..2.37 rows=106 width=0)               Index Cond: (unique1 &lt; 100)   -&gt;  Index Scan using tenk2_unique2 on tenk2 t2  (cost=0.00..3.01 rows=1 width=244)         Index Cond: ("outer".unique2 = t2.unique2)</programlisting>   </para>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -