2013-02-26 22 views
6

Tôi đang sử dụng datatables để hiển thị dữ liệu từ nhiều bảng mySQL (7 trong số chúng thực sự). Hiện tại không có nhiều dữ liệu, nhưng tôi thấy "Hiển thị 1 đến 7 trong số 7 mục (được lọc từ 642,660,480 tổng số mục nhập)." và mất 20 giây để chỉ hiển thị 7 mục nhập. Khi tôi thực sự bắt đầu thêm nhiều nội dung vào cơ sở dữ liệu, tôi chắc chắn điều này sẽ không thể sử dụng được.DataTables: Tăng tốc xử lý phía máy chủ với nhiều bảng, nhóm và nội dung html?

Tôi chắc chắn rằng có những cách tốt hơn để hoàn thành những gì tôi đang cố gắng làm, nhưng đây là cách duy nhất tôi có thể làm cho nó hoạt động.

Đây là kịch bản phía máy chủ của tôi:

$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); 

Đây là truy vấn mà kịch bản phía máy chủ được tạo ra:

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 

Tôi đang cố gắng để xác định những gì tôi có thể làm để tối ưu hóa này mà không vi phạm các tính năng tìm kiếm và sắp xếp của datatables. Tôi đã tạo các chỉ mục và đặt các khóa chính cho tất cả các bảng là tốt nhất như tôi biết. Có cách nào để sử dụng JOIN có thể?

Đây là kết quả của giải thích tuyên bố:

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 

UPDATE:

Vấn đề dường như đã là một vấn đề với việc sử dụng bao gồm cả người sử dụng và bảng sự kiện trong truy vấn (không phải trong đó đã thực sự được sử dụng). Đây là mã sửa đổi thực thi nhanh hơn nhiều:

$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); 

Nếu tôi được sử dụng tham gia, truy vấn cập nhật sẽ là:

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 

Vấn đề với điều này là DataTables chỉ không được thiết kế để hoạt động chính xác với JOINS khi sắp xếp và lọc được sử dụng do mảng cột, v.v. Tôi rất thích xem giải pháp có thể hoạt động với truy vấn như thế này.

+0

add 'EXPLAIN' vào phía trước của các lựa chọn và xem những gì nó nói –

+0

ngồi biên tập cho thấy kết quả của GIẢI THÍCH – compcentral

+0

Hi i am cũng phải đối mặt với cùng một vấn đề + tìm kiếm của tôi cũng đang hiển thị hồ sơ thêm vì JOIN và nơi có điều kiện. .xin vui lòng bạn có thể giúp tôi ..http: //stackoverflow.com/questions/25015124/datatables-searching-at-server-side-php-mysql – user3209031

Trả lời

5

Để bắt đầu, nếu bạn muốn tối ưu hóa một câu lệnh SQL, trước tiên hãy loại bỏ crap HTML trong đó. Nếu không có gì khác, nó làm xáo trộn cấu trúc thực tế của Tuyên bố. Nếu bạn phải, bạn có thể đặt nó trở lại vào cuối tối ưu hóa của bạn, mặc dù tôi nghiêm túc bỏ phiếu chống lại nó: Bạn đã có PHP để làm đánh dấu. Vì lợi ích của sự rõ ràng tôi đã làm cho nó một thói quen sử dụng JOIN mệnh đề, tôi rephrased toàn bộ Thing cho phù hợp.

gì quá trình này đã cho tôi là thế này:

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 

Có một vài điều cần được quan sát thấy ở đây:

1) bảng chính của bạn là orders. Đó cũng là một trong những bạn đang sử dụng mệnh đề WHERE cho VÀ bạn đang GROUP BY đó. Với id làm chỉ mục chính và chỉ mục thứ hai trên status, điều này không quá tệ.

2) Bạn đang liên kết trong bốn bảng khác thông qua tôi được giả định là khóa ngoại. Hai trong số các bảng đó không bao giờ thực sự được sử dụng: có (có thể là hầu hết) không cần phải tham gia vào số usersevents. Bạn nên loại bỏ những thứ đó, điều này cũng sẽ loại bỏ sự tham gia ít hơn so với sao trên một cột văn bản (tên người dùng). Đảm bảo các bảng còn lại doctorspatients có các khóa chính trên các cột id tương ứng của chúng.

3) Bạn có sự tham gia phức tạp hơn trên hai bảng tests_orderedtests. Tất cả những gì làm là cung cấp cho bạn một chuỗi các tên được nối, nhưng nó thêm vào sự phức tạp của mệnh đề GROUP BY. Có hai cách để đi từ đây: cố gắng tối ưu hóa các kết nối đó hoặc loại bỏ chúng tạo thành lựa chọn hoàn toàn.

3) Dung dịch A Để tối ưu hóa những tham gia, hãy chắc chắn bạn đã có một chỉ mục trên tests_ordered.order_id và trên tests_ordered.test_id và một chỉ số chính về tests.id. Bản Tuyên Bố của bạn sẽ giống như thế này:

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) Giải pháp B Tháo kiểm tra toàn bộ/stuff tests_ordered, và đặt nó trong một lựa chọn riêng biệt. chọn chính của bạn bây giờ sẽ trông như thế này:

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' 

Nhưng bạn hoặc sẽ phải chạy thêm CHỌN mỗi hàng để có được t.name nối hoặc bạn làm chỉ là một CHỌN cho tất cả id trật tự trên trang hiện tại . Hình sau sẽ giống như sau:

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 

Giải pháp A nên chạy khá nhanh trên máy phong nha. Giải pháp B nên chạy khá nhanh trên bất kỳ máy nào. JOINs thẳng trên các khóa ngoài được lập chỉ mục là rẻ.

4) Không có lựa chọn nào ở trên nên trả lại 642 triệu hàng trên cơ sở dữ liệu có ít hơn 642 triệu đơn đặt hàng trong đó, mà tôi cho là bạn không làm. Kể từ khi MySQL nói với bạn rằng nó có thể đã phải xây dựng một sản phẩm đầy đủ Descartes, mà cũng giải thích tốc độ kinh nghiệm. Điều đó có nghĩa là một trong những chìa khóa nước ngoài của bạn tham gia đi haywire.Nhiều khả năng người được đề cập là tham gia vào số users - một sự tham gia vô dụng ngay từ đầu, nhưng trong mọi trường hợp: hãy kiểm tra tính duy nhất của cột username của nó.

+0

cảm ơn đã chỉ đạo tôi đi đúng hướng. vấn đề là với các bảng không sử dụng, loại bỏ người dùng và các bảng sự kiện đã giải quyết được vấn đề. Chỉ cần thực hiện việc đó đã giảm thời gian truy vấn xuống còn 0,0035 giây từ 20 giây trở lên. Tôi muốn sử dụng tham gia và không sử dụng quá nhiều html trong truy vấn, nhưng DataTables không hoạt động chính xác sau đó. Tôi sẽ đăng mã cố định ngay. – compcentral

+0

Nhân tiện, không có câu lệnh SQL nào mà bạn đã đăng thực sự hoạt động .. lỗi cú pháp nhỏ. Không cần dấu phẩy sau SQL_CALC_FOUND_ROWS. Sử dụng kết nối, truy vấn sẽ giống như những gì tôi có trong bài đăng cập nhật của mình. – compcentral

+0

Thiếu một bản sao của cấu trúc cơ sở dữ liệu của bạn, tôi đã viết các câu lệnh SQL từ phía sau đầu của tôi.Vì vậy, có, họ rất có thể có lỗi cú pháp nhỏ - cảm thấy tự do để chỉnh sửa bài đăng của tôi cho phù hợp. Về HTML trong truy vấn, bạn nói đúng, bạn cần thêm nó ở đâu đó - nhưng làm như vậy trong SQL chỉ là một cách kỳ lạ (và tốn kém) để làm như vậy, bạn đã có PHP cho điều đó. – Hazzit

0

1) Một vài gợi ý có thể là xóa tất cả các bản concats và các chức năng không cần thiết mà bạn có thể sử dụng PHP trong lớp trình bày và chỉ chọn các giá trị cột.

2) Chỉ chọn các cột quan trọng nhất là hoàn toàn không chính xác trong lược đồ của bạn và sau đó bạn có thể chạy các lựa chọn 1 dòng đơn giản cho các thuộc tính khác. (mặc dù số lượng truy vấn có thể tăng lên nhưng thực tế nó có thể tăng tốc hiệu suất vì nhiều kết nối có xu hướng rất chậm)

3) Nếu không có gì giúp bạn có thể dẫn đến một số hình thức không chuẩn hóa, nơi bạn phải sao chép một số mối quan hệ nhất định giá trị trên nhiều bảng để giảm số lượng kết nối.

4) Cache, bộ nhớ cache, cahce - trên mức cơ sở dữ liệu, vào mức độ php, về cơ bản ở khắp mọi nơi ...

5) Ngoài ra nó phụ thuộc rất nhiều vào dữ liệu của bạn ví dụ của những 700 000 000 hàng nếu bạn chỉ cần sử dụng 100 000 000 gần đây nhất sau đó phát triển một số tính năng lưu trữ để giảm số lượng bản ghi trong bảng hoạt động và chỉ khi bản ghi trong kho lưu trữ, sau đó tìm kiếm qua bảng lưu trữ lớn có thể chậm nhưng sẽ xảy ra nhiều hơn rất nhiều ...

Đó chỉ là một vài nhược điểm rất chung chung.

0

Trong bổ sung cho câu trả lời @azzit đẹp tôi có thể cung cấp cho bạn một số gợi ý mà chúng tôi đã sử dụng trên datatables máy chủ truy vấn phụ:

  • tránh nhóm concat, điều này sẽ luôn làm cho truy vấn của bạn rất chậm, thậm chí có thể sử dụng các bảng tạm thời, một thứ bạn nên tránh. Vì vậy, thay vì chờ kết quả được phân trang của bạn và khởi chạy dữ liệu bổ sung (như ở đây dữ liệu tests_ordered) dựa trên số nhận dạng thực tế được trả về sau khi phân trang truy vấn chính
  • giải pháp được sử dụng ở trên có thể trở thành vấn đề nếu bạn phải lọc truy vấn chính trên các phần tử tests_ordered . Nhưng trên thực tế, giải pháp là thêm EXISTS các lựa chọn để lọc truy vấn chính của bạn trên các đề tài 1-> n có liên quan (và với các truy vấn con hiện tại, bạn sẽ không cần các bảng trong truy vấn chính của mình, chỉ trên subselect khi bộ lọc được áp dụng)
  • Đặt một số truy vấn đếm với các điều kiện và điều kiện cần thiết và cố gắng ghi lại kết quả trong khi bộ lọc không bị sửa đổi (bạn có thể bỏ qua thứ tự bằng cách sửa đổi).
  • xem ra cho yêu cầu, bạn không được phép sử dụng tất cả các cột theo thứ tự. Sắp xếp theo sẽ nhận được truy vấn của bạn rất chậm nếu một cột không được lập chỉ mục được sử dụng. Đặc biệt, bạn không nên cho phép đặt hàng bằng các cột 'nhiều giá trị' như tests_ordered.
  • Nếu bạn có số lượng lớn tham gia và bạn cho rằng truy vấn của mình được viết theo thứ tự đúng, hãy sử dụng STRAIGHT_JOIN trên lựa chọn để tránh mất giây trong tính toán trình tối ưu hóa (heppen với số lượng tham gia thực sự lớn).
  • Sử dụng kết nối trái cho các cột có thể trống (không), nhưng cố gắng tránh đặt chúng trong truy vấn nếu dữ liệu này không được sử dụng theo thứ tự bởi, bộ lọc hoặc không được hiển thị trong cột hiển thị.
  • kiểm tra truy vấn của bạn với giải thích, đừng ngần ngại thêm các biến thể trên bộ lọc và oreder theo. Bạn sẽ thấy rằng việc sử dụng các hàm như FROM_UNIXTIME có thể ngăn việc sử dụng chỉ mục.
  • chiến lược được sử dụng cho nhiều cột giá trị luôn có thể được áp dụng cho tất cả các cột, thực hiện truy vấn tối thiểu để nhận số nhận dạng kết quả được phân trang của bạn (chỉ định danh trong cột, thêm tham gia được yêu cầu cho điều kiện hoặc thứ tự bằng cách thêm tùy chọn cho nhiều truy vấn giá trị điều kiện), đếm kết quả toàn cầu và áp dụng phân trang trên đó. Sau đó, trên các kết quả 10/25/50/100 thu được tải tất cả dữ liệu ô dựa trên số nhận dạng hàng.
Các vấn đề liên quan