7

私はデータテーブルを使用して、複数のmySQLテーブル(実際には7つ)からのデータを表示しています。現在、実際には多くのデータはありませんが、「7つのエントリのうち1つから7つを表示しています(合計642,660,480のエントリからフィルタリング)」と表示されます。7つのエントリのみを表示するのに20秒かかります。データベースに大量のコンテンツを追加し始めると、これは使用できなくなると確信しています。

私がやろうとしていることを達成するためのより良い方法があると確信していますが、これが私がそれを機能させることができた唯一の方法です。

これが私のサーバーサイドスクリプトです:

$q1 = "'";
$q2 = '"';

$order_id = "CONCAT( ".$q2."<input type='hidden' id='order_id' value='".$q2.", o.id, ".$q2."'><a href='order_details.php?id=".$q2.", o.id, ".$q2."'><img src='https://pas.greysignal.com/img/search.png' border='0'></a> &nbsp;".$q2.", o.id )";
$patient_name = "CONCAT( ".$q2."<input type='hidden' id='patient_name' value='".$q2.", p.first_name, ' ', p.last_name, ".$q2."'><input type='hidden' id='patient_id' value='".$q2.", p.id, ".$q2."'><input type='hidden' id='patient_ssn' value='".$q2.", p.ssn, ".$q2."'><a href='patient_details.php?id=".$q2.", p.id, ".$q2."'><img src='https://pas.greysignal.com/img/search.png' border='0'></a> &nbsp;".$q2.", p.first_name, ' ', p.last_name )";
$doc_name = "CONCAT( ".$q2."<input type='hidden' id='doctor_name' value='".$q2.", d.first_name, ' ', d.last_name, ".$q2."'><input type='hidden' id='doctor_id' value='".$q2.", d.id, ".$q2."'><a href='doctor_details.php?id=".$q2.", d.id, ".$q2."'><img src='https://pas.greysignal.com/img/search.png' border='0'></a> &nbsp;".$q2.", d.first_name, ' ', d.last_name )";
$order_date = "FROM_UNIXTIME(o.created_timestamp, '%m/%e/%Y')";
$tests = "GROUP_CONCAT(t.name SEPARATOR ', ')";

$aColumns = array($order_id, $order_date, $doc_name, $patient_name, $tests, 'o.status');

/* Indexed column (used for fast and accurate table cardinality) */
$sIndexColumn = "o.id";

/* DB table to use */
$sTable = "`orders` o, `patients` p, `doctors` d, `tests_ordered` tst, `tests` t, `users` u, `events` e";

$sWhere = "WHERE p.id = o.patient_id AND d.id = o.doctor_id AND tst.order_id = o.id AND t.id = tst.test_id AND u.username = o.assigned_username AND e.event_id = o.event_id";
$order_status = isset($_GET['status']) ? $_GET['status'] : 'all';
if($order_status == 'all'){

}else{
    $sWhere .= " AND (o.status='Complete' OR o.status='$order_status')";
}

$sGroupBy =  "GROUP BY o.id";

/* Database connection information */
$gaSql['user']       = DB_USER;
$gaSql['password']   = DB_PASSWORD;
$gaSql['db']         = DB_NAME;
$gaSql['server']     = DB_SERVER;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * If you just want to use the basic configuration for DataTables with PHP server-side, there is
 * no need to edit below this line
 */

/* 
 * MySQL connection
 */
$gaSql['link'] =  mysql_pconnect( $gaSql['server'], $gaSql['user'], $gaSql['password']  ) or
    die( 'Could not open connection to server' );

mysql_select_db( $gaSql['db'], $gaSql['link'] ) or 
    die( 'Could not select database '. $gaSql['db'] );

/* 
 * Paging
 */
$sLimit = "";
if ( isset( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' )
{
    $sLimit = "LIMIT ".mysql_real_escape_string( $_GET['iDisplayStart'] ).", ".
        mysql_real_escape_string( $_GET['iDisplayLength'] );
}

/*
 * Ordering
 */
if ( isset( $_GET['iSortCol_0'] ) )
{
    $sOrder = "ORDER BY  ";
    for ( $i=0 ; $i<intval( $_GET['iSortingCols'] ) ; $i++ )
    {
        if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == "true" )
        {
            $sOrder .= $aColumns[ intval( $_GET['iSortCol_'.$i] ) ]."
                ".mysql_real_escape_string( $_GET['sSortDir_'.$i] ) .", ";
        }
    }

    $sOrder = substr_replace( $sOrder, "", -2 );
    if ( $sOrder == "ORDER BY" )
    {
        $sOrder = "";
    }
}

/* 
 * Filtering
 * NOTE this does not match the built-in DataTables filtering which does it
 * word by word on any field. It's possible to do here, but concerned about efficiency
 * on very large tables, and MySQL's regex functionality is very limited
 */

if ( $_GET['sSearch'] != "" )
{
    $sWhere .= " AND (";
    for ( $i=0 ; $i<count($aColumns) ; $i++ )
    {
if($i!=4){ //skip tests column
        $sWhere .= $aColumns[$i]." LIKE '%".mysql_real_escape_string( $_GET['sSearch'] )."%' OR ";
}
    }
    $sWhere = substr_replace( $sWhere, "", -3 );
    $sWhere .= ')';
}

/* Individual column filtering */
for ( $i=0 ; $i<count($aColumns) ; $i++ )
{
if($i!=4){ //skip tests column
    if ( $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' )
    {
        if ( $sWhere == "" )
        {
            $sWhere = "WHERE ";
        }
        else
        {
            $sWhere .= " AND ";
        }
        $sWhere .= $aColumns[$i]." LIKE '%".mysql_real_escape_string($_GET['sSearch_'.$i])."%' ";
    }
}
}


/*
 * SQL queries
 * Get data to display
 */
$sQuery = "
    SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
    FROM   $sTable
    $sWhere
    $sGroupBy 
    $sOrder
    $sLimit
";

//echo $sQuery;
//die();

$rResult = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());

/* Data set length after filtering */
$sQuery = "
    SELECT FOUND_ROWS()
";
$rResultFilterTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
$aResultFilterTotal = mysql_fetch_array($rResultFilterTotal);
$iFilteredTotal = $aResultFilterTotal[0];

/* Total data set length */
$sQuery = "
    SELECT COUNT(".$sIndexColumn.")
    FROM   $sTable
";
$rResultTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
$aResultTotal = mysql_fetch_array($rResultTotal);
$iTotal = $aResultTotal[0];

//added to hide filtering   
//$iTotal = $iFilteredTotal;

/*
 * Output
 */
$output = array(
    "sEcho" => intval($_GET['sEcho']),
    "iTotalRecords" => $iTotal,
    "iTotalDisplayRecords" => $iFilteredTotal,
    "aaData" => array()
);

while ( $aRow = mysql_fetch_array( $rResult ) )
{
    $row = array();
    for ( $i=0 ; $i<count($aColumns) ; $i++ )
    {
        if ( $aColumns[$i] != ' ' )
        {
            /* General output */
            $row[] = $aRow[$i];
        }
    }
    $output['aaData'][] = $row;
}

echo json_encode( $output );

サーバーサイドスクリプトが生成しているクエリは次のとおりです。

SELECT SQL_CALC_FOUND_ROWS 
    CONCAT( "<input type='hidden' id='order_id' value='", o.id, "'><a href='order_details.php?id=", o.id, "'><img src='search.png' border='0'></a> &nbsp;", o.id ),
    FROM_UNIXTIME(o.created_timestamp, '%m/%e/%Y'),
    CONCAT( "<input type='hidden' id='doctor_name' value='", d.first_name, ' ', d.last_name, "'><input type='hidden' id='doctor_id' value='", d.id, "'><a href='doctor_details.php?id=", d.id, "'><img src='search.png' border='0'></a> &nbsp;", d.first_name, ' ', d.last_name ),
    CONCAT( "<input type='hidden' id='patient_name' value='", p.first_name, ' ', p.last_name, "'><input type='hidden' id='patient_id' value='", p.id, "'><input type='hidden' id='patient_ssn' value='", p.ssn, "'><a href='patient_details.php?id=", p.id, "'><img src='search.png' border='0'></a> &nbsp;", p.first_name, ' ', p.last_name ), GROUP_CONCAT(t.name SEPARATOR ', '),
    o.status
FROM `orders` o, `patients` p, `doctors` d, `tests_ordered` tst, `tests` t, `users` u, `events` e
WHERE p.id = o.patient_id AND d.id = o.doctor_id AND tst.order_id = o.id AND t.id = tst.test_id AND u.username = o.assigned_username AND e.event_id = o.event_id AND (o.status='Complete' OR o.status='Draft')
GROUP BY o.id

私は、データテーブルの検索機能と並べ替え機能を壊すことなく、これを最適化するために何ができるかを判断しようとしています。インデックスを作成し、すべてのテーブルに主キーを設定しました。JOINを使用する方法はありますか?

EXPLAINステートメントの出力は次のとおりです。

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  u   index   NULL    PRIMARY 32  NULL    5   Using index; Using temporary; Using filesort
1   SIMPLE  o   ALL PRIMARY,patient_id,doctor_id,event_id,assigned_use...   NULL    NULL    NULL    6   Using where
1   SIMPLE  d   eq_ref  PRIMARY PRIMARY 4   pasdbadmin.o.doctor_id  1    
1   SIMPLE  e   eq_ref  PRIMARY PRIMARY 4   pasdbadmin.o.event_id   1   Using index
1   SIMPLE  tst ref order_id,test_id    order_id    4   pasdbadmin.o.id 1    
1   SIMPLE  t   eq_ref  PRIMARY PRIMARY 4   pasdbadmin.tst.test_id  1    
1   SIMPLE  p   eq_ref  PRIMARY PRIMARY 4   pasdbadmin.o.patient_id 1

アップデート:

問題は、クエリにユーザーテーブルとイベントテーブルを含めることに関する問題のようです(どちらも実際には使用されていません)。はるかに高速に実行される改訂されたコードは次のとおりです。

$q1 = "'";
$q2 = '"';

$order_id = "CONCAT( ".$q2."<input type='hidden' id='order_id' value='".$q2.", o.id, ".$q2."'><a href='order_details.php?id=".$q2.", o.id, ".$q2."'><img src='https://pas.greysignal.com/img/search.png' border='0'></a> &nbsp;".$q2.", o.id )";
$patient_name = "CONCAT( ".$q2."<input type='hidden' id='patient_name' value='".$q2.", p.first_name, ' ', p.last_name, ".$q2."'><input type='hidden' id='patient_id' value='".$q2.", p.id, ".$q2."'><input type='hidden' id='patient_ssn' value='".$q2.", p.ssn, ".$q2."'><a href='patient_details.php?id=".$q2.", p.id, ".$q2."'><img src='https://pas.greysignal.com/img/search.png' border='0'></a> &nbsp;".$q2.", p.first_name, ' ', p.last_name )";
$doc_name = "CONCAT( ".$q2."<input type='hidden' id='doctor_name' value='".$q2.", d.first_name, ' ', d.last_name, ".$q2."'><input type='hidden' id='doctor_id' value='".$q2.", d.id, ".$q2."'><a href='doctor_details.php?id=".$q2.", d.id, ".$q2."'><img src='https://pas.greysignal.com/img/search.png' border='0'></a> &nbsp;".$q2.", d.first_name, ' ', d.last_name )";
$order_date = "FROM_UNIXTIME(o.created_timestamp, '%m/%e/%Y')";
$tests = "GROUP_CONCAT(t.name SEPARATOR ', ')";

$aColumns = array($order_id, $order_date, $doc_name, $patient_name, $tests, 'o.status');

/* Indexed column (used for fast and accurate table cardinality) */
$sIndexColumn = "o.id";

/* DB table to use */
$sTable = "`orders` o, `patients` p, `doctors` d, `tests_ordered` tst, `tests` t";

$sWhere = "WHERE p.id = o.patient_id AND d.id = o.doctor_id AND tst.order_id = o.id AND t.id = tst.test_id";
$order_status = isset($_GET['status']) ? $_GET['status'] : 'all';
if($order_status == 'all'){

}else{
    $sWhere .= " AND (o.status='Complete' OR o.status='$order_status')";
}

$sJoin = "";

$sGroupBy =  "GROUP BY o.id";

/* Database connection information */
$gaSql['user']       = DB_USER;
$gaSql['password']   = DB_PASSWORD;
$gaSql['db']         = DB_NAME;
$gaSql['server']     = DB_SERVER;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * If you just want to use the basic configuration for DataTables with PHP server-side, there is
 * no need to edit below this line
 */

/* 
 * MySQL connection
 */
$gaSql['link'] =  mysql_pconnect( $gaSql['server'], $gaSql['user'], $gaSql['password']  ) or
    die( 'Could not open connection to server' );

mysql_select_db( $gaSql['db'], $gaSql['link'] ) or 
    die( 'Could not select database '. $gaSql['db'] );

/* 
 * Paging
 */
$sLimit = "";
if ( isset( $_GET['iDisplayStart'] ) && $_GET['iDisplayLength'] != '-1' )
{
    $sLimit = "LIMIT ".mysql_real_escape_string( $_GET['iDisplayStart'] ).", ".
        mysql_real_escape_string( $_GET['iDisplayLength'] );
}

/*
 * Ordering
 */
if ( isset( $_GET['iSortCol_0'] ) )
{
    $sOrder = "ORDER BY  ";
    for ( $i=0 ; $i<intval( $_GET['iSortingCols'] ) ; $i++ )
    {
        if ( $_GET[ 'bSortable_'.intval($_GET['iSortCol_'.$i]) ] == "true" )
        {
            $sOrder .= $aColumns[ intval( $_GET['iSortCol_'.$i] ) ]."
                ".mysql_real_escape_string( $_GET['sSortDir_'.$i] ) .", ";
        }
    }

    $sOrder = substr_replace( $sOrder, "", -2 );
    if ( $sOrder == "ORDER BY" )
    {
        $sOrder = "";
    }
}

/* 
 * Filtering
 * NOTE this does not match the built-in DataTables filtering which does it
 * word by word on any field. It's possible to do here, but concerned about efficiency
 * on very large tables, and MySQL's regex functionality is very limited
 */

if ( $_GET['sSearch'] != "" )
{
    $sWhere .= " AND (";
    for ( $i=0 ; $i<count($aColumns) ; $i++ )
    {
        if($i!=4){ //skip tests column
            $sWhere .= $aColumns[$i]." LIKE '%".mysql_real_escape_string( $_GET['sSearch'] )."%' OR ";
        }
    }
    $sWhere = substr_replace( $sWhere, "", -3 );
    $sWhere .= ')';
}

/* Individual column filtering */
for ( $i=0 ; $i<count($aColumns) ; $i++ )
{
    if($i!=4){ //skip tests column
        if ( $_GET['bSearchable_'.$i] == "true" && $_GET['sSearch_'.$i] != '' )
        {
            if ( $sWhere == "" )
            {
                $sWhere = "WHERE ";
            }
            else
            {
                $sWhere .= " AND ";
            }
            $sWhere .= $aColumns[$i]." LIKE '%".mysql_real_escape_string($_GET['sSearch_'.$i])."%' ";
        }
    }
}


/*
 * SQL queries
 * Get data to display
 */
$sQuery = "
    SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
    FROM   $sTable
    $sWhere
    $sJoin
    $sGroupBy 
    $sOrder
    $sLimit
";

$filename = __DIR__.DIRECTORY_SEPARATOR."sql_log.txt";
file_put_contents($filename, $sQuery, FILE_APPEND);

$rResult = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());

/* Data set length after filtering */
$sQuery = "
    SELECT FOUND_ROWS()
";
$rResultFilterTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
$aResultFilterTotal = mysql_fetch_array($rResultFilterTotal);
$iFilteredTotal = $aResultFilterTotal[0];

/* Total data set length */
$sQuery = "
    SELECT COUNT(".$sIndexColumn.")
    FROM   $sTable
";
$rResultTotal = mysql_query( $sQuery, $gaSql['link'] ) or die(mysql_error());
$aResultTotal = mysql_fetch_array($rResultTotal);
$iTotal = $aResultTotal[0];

//added to hide filtering   
//$iTotal = $iFilteredTotal;

/*
 * Output
 */
$output = array(
    "sEcho" => intval($_GET['sEcho']),
    "iTotalRecords" => $iTotal,
    "iTotalDisplayRecords" => $iFilteredTotal,
    "aaData" => array()
);

while ( $aRow = mysql_fetch_array( $rResult ) )
{
    $row = array();
    for ( $i=0 ; $i<count($aColumns) ; $i++ )
    {
        if ( $aColumns[$i] != ' ' )
        {
            /* General output */
            $row[] = $aRow[$i];
        }
    }
    $output['aaData'][] = $row;
}

echo json_encode( $output );

JOINSを使用する場合、更新されるクエリは次のようになります。

 SELECT SQL_CALC_FOUND_ROWS 
     CONCAT( "<input type='hidden' id='order_id' value='", o.id, "'><a href='order_details.php?id=", o.id, "'><img src='search.png' border='0'></a> &nbsp;", o.id ),
     FROM_UNIXTIME(o.created_timestamp, '%m/%e/%Y'),
     CONCAT( "<input type='hidden' id='doctor_name' value='", d.first_name, ' ', d.last_name, "'><input type='hidden' id='doctor_id' value='", d.id, "'><a href='doctor_details.php?id=", d.id, "'><img src='search.png' border='0'></a> &nbsp;", d.first_name, ' ', d.last_name ),
     CONCAT( "<input type='hidden' id='patient_name' value='", p.first_name, ' ', p.last_name, "'><input type='hidden' id='patient_id' value='", p.id, "'><input type='hidden' id='patient_ssn' value='", p.ssn, "'><a href='patient_details.php?id=", p.id, "'><img src='search.png' border='0'></a> &nbsp;", p.first_name, ' ', p.last_name ),
     GROUP_CONCAT(t.name SEPARATOR ', '),
     o.status
 FROM `orders` o
 JOIN `doctors` d ON d.id = o.doctor_id
 JOIN `patients` p ON p.id = o.patient_id
 JOIN `tests_ordered` tst ON tst.order_id = o.id
 JOIN `tests` t ON t.id = tst.test_id 
 WHERE o.status='Complete' OR o.status='Draft'
 GROUP BY o.id

これに伴う問題は、列配列などのために並べ替えやフィルタリングが使用されている場合、DataTablesがJOINSで正しく機能するように設計されていないことです。ただし、このようなクエリで機能するソリューションを探しています。

4

3 に答える 3

5

まず、SQLステートメントを最適化する場合は、まず、そこにあるHTMLのがらくたを取り除きます。他に何もないとしても、それはステートメントの実際の構造を曖昧にします。必要に応じて、最適化の最後に戻すことができますが、私は真剣に反対票を投じます。マークアップを行うにはPHPが必要です。わかりやすくするために、JOIN句を使用することを習慣にしました。それに応じて、Thing全体を言い換えました。

このプロセスが私に与えたのはこれでした:

SELECT SQL_CALC_FOUND_ROWS,
    o.id, o.created_timestamp, o.status,
    d.id, d.first_name, d.last_name, 
    p.id, p.first_name, p.last_name, p.ssn 
    GROUP_CONCAT(t.name SEPARATOR ', '),
FROM `orders` o
JOIN `doctors` d ON d.id = o.doctor_id
JOIN `patients` p ON p.id = o.patient_id
JOIN `users` u ON u.username = o.assigned_username
JOIN `events` e ON e.event_id = o.event_id
JOIN `tests_ordered` tst ON tst.order_id = o.id
JOIN `tests` t ON t.id = tst.test_id 
WHERE o.status='Complete' OR o.status='Draft'
GROUP BY o.id

ここで注意すべきことがいくつかあります。

1)メインテーブルはordersです。これは、WHERE句を使用していて、それによってGROUPINGしているものでもあります。idプライマリインデックスとセカンドインデックスとして、statusこれはそれほど悪くないはずです。

2)他の4つのテーブルにリンクしているのは、外部キーであると想定した場合です。これらのテーブルのうちの2つは、実際には使用されません。(ほとんどの場合)結合する必要はまったくありませusersevents。それらを取り除く必要があります。これにより、テキスト列(ユーザー名)の恒星未満の結合も削除されます。残りのテーブルdoctorspatients、それぞれidの列に主キーがあることを確認してください。

3)tests_ordered 2つのテーブルと。でより複雑な結合がありtestsます。名前の連結文字列を提供するだけですが、GROUPBY句の複雑さが増します。ここから先に進むには2つの方法があります。それらの結合を最適化するか、選択から完全に削除するかです。

3)ソリューションAこれらの結合を最適化するには、にインデックスがあり、にプライマリインデックスがあることを確認しtests_ordered.order_idtests_ordered.test_idくださいtests.id。ステートメントは次のようになります。

SELECT SQL_CALC_FOUND_ROWS,
    o.id, o.created_timestamp, o.status,
    d.id, d.first_name, d.last_name, 
    p.id, p.first_name, p.last_name, p.ssn 
    GROUP_CONCAT(t.name SEPARATOR ', '),
FROM `orders` o
JOIN `doctors` d ON d.id = o.doctor_id
JOIN `patients` p ON p.id = o.patient_id
JOIN `tests_ordered` tst ON tst.order_id = o.id
JOIN `tests` t ON t.id = tst.test_id 
WHERE o.status='Complete' OR o.status='Draft'
GROUP BY o.id

3)解決策B tests / tests_orderedのもの全体を削除し、別の選択に入れます。メインの選択は次のようになります。

SELECT SQL_CALC_FOUND_ROWS,
    o.id, o.created_timestamp, o.status,
    d.id, d.first_name, d.last_name, 
    p.id, p.first_name, p.last_name, p.ssn 
FROM `orders` o
JOIN `doctors` d ON d.id = o.doctor_id
JOIN `patients` p ON p.id = o.patient_id
WHERE o.status='Complete' OR o.status='Draft'

ただし、連結されたt.nameを取得するには、行ごとに追加のSELECTを実行するか、現在のページのすべての注文IDに対して1つのSELECTを実行する必要があります。後者は次のようになります。

SELECT o.id, GROUP_CONCAT(t.name SEPARATOR ', '),
FROM `orders` o
JOIN `tests_ordered` tst ON tst.order_id = o.id
JOIN `tests` t ON t.id = tst.test_id 
WHERE o.in IN ( <put the 10 ids on your current page here, separated by commas> )
GROUP BY o.id

解決策Aは、まともなマシンでかなり速く実行されるはずです。ソリューションBは、どのマシンでも非常に高速に実行されるはずです。インデックス付き外部キーのストレート結合は安価です。

4)上記の選択のいずれも、6億4200万件未満の注文があるデータベースで6億4200万行を返すことはできませんが、そうではないと思います。MySQLは、おそらく完全なデカルト積を作成する必要があると言っているので、これは経験豊富な速度も説明しています。これは、直接外部キー結合の1つが失敗したことを意味します。おそらく問題の1つは結合ですusers-そもそも役に立たない結合ですが、いずれにせよ、そのusername列の一意性を確認してください。

于 2013-03-01T00:40:24.210 に答える
0

1)いくつかのヒントは、プレゼンテーション層でPHPを使用できるすべての連結関数と不要な関数を削除し、列の値のみを選択することです。

2)スキーマで絶対的に重要な最も重要な列のみを選択すると、他の属性に対して単純な1行の選択を実行できます。(クエリの数が増える可能性がありますが、複数の結合は非常に遅い傾向があるため、実際にはパフォーマンスを高速化できます)

3)何も役に立たない場合は、結合の量を減らすために複数のテーブルに特定の関係値をコピーする必要がある、何らかの形式の非正規化が必要になる場合があります。

4)キャッシュ、キャッシュ、キャッシュ-データベースレベル、phpレベル、基本的にどこでも...

5)また、最新の100 000 000を実際に利用するだけでよい場合は、データに大きく依存します。たとえば、運用テーブルのレコード数を減らすために、何らかのアーカイブ機能を開発します。レコードがアーカイブにあり、大きなアーカイブテーブルを検索します。これは遅いかもしれませんが、非常にまれにしか発生しません...

これらは、ごく一般的な考えのほんの一部です。

于 2013-02-28T19:32:12.730 に答える
0

@azzitの良い答えを補完するものとして、datatablesサーバー側のクエリで使用したヒントをいくつか紹介します。

  • グループ連結を避けてください。これにより、一時テーブルを使用している場合でも、クエリが常に非常に遅くなります。これは避ける必要があります。したがって、代わりに、ページ付けされた結果を待ち、メインクエリのページ付け後に返された実際の識別子に基づいて追加のデータ(ここではtests_orderedデータなど)を起動します
  • 上記で使用したソリューションは、tests_ordered要素でメインクエリをフィルタリングする必要がある場合に問題になる可能性があります。しかし実際の解決策は、これらの1-> n関連テーブルのメインクエリにEXISTSサブセレクトを追加することです(既存のサブクエリでは、メインクエリにこれらのテーブルは必要ありません。フィルターが適用された場合のサブセレクトにのみ必要です)
  • 必要な結合と条件を使用して1つのカウントクエリを作成し、フィルターが変更されていないときに結果を記録してみます(変更による順序は無視できます)。
  • 順序付けに注意してください。すべての列を順序付けで使用できるようにしないください。インデックス付けされていない列が使用されている場合、順序付けを行うとクエリが非常に遅くなります。特に、tests_orderedのような「複数の値」列での順序付けを許可しないでください。
  • 結合の数が多く、クエリが正しい順序で記述されていると思われる場合は、オプティマイザーの計算で秒数が失われないように、選択でSTRAIGHT_JOINを使用します(結合の数が非常に多いヘッペン)。
  • 空(null)の可能性がある列には左結合を使用しますが、このデータがフィルターによって順番に使用されていない場合、または表示されている列にない場合は、クエリに入れないようにしてください。
  • Explainを使用してクエリをテストし、フィルターとorederにバリエーションを追加することを躊躇しないでください。FROM_UNIXTIMEのような関数を使用すると、インデックスの使用を防ぐことができることがわかります。
  • 複数の値の列に使用される戦略は、常にすべての列に適用でき、ページ分割された結果識別子を取得するために最小限のクエリを実行します(列の識別子のみ、条件または順序付けのために要求された結合を追加し、条件を持つ複数の値のクエリの副選択を追加します)、グローバル結果をカウントし、それにページ付けを適用します。次に、取得した10/25/50/100の結果で、行識別子に基づいてすべてのセルデータをロードします。
于 2013-03-06T12:59:37.807 に答える