In oder to avoid confusion like this, I always use sprintf() where I need to concatenate strings
Change:
global $wpdb;
if ( isset ( $_POST['id'] ) && ! empty ( $_POST['id']  )) {
    $wpdb->query("DELETE " . PRO_TABLE_PREFIX . "tutorial  WHERE id='{$_POST['id']}'");
}
to:
global $wpdb;
if ( isset ( $_POST['id'] ) )) {    
   $wpdb->query(sprintf("DELETE %stutorial  WHERE id='%s'", PRO_TABLE_PREFIX, $_POST['id']));
}
A couple of things to note:
1) You're vulnerable to SQL injection
2) Once you've used isset() to determine if the key of $_POST['id'] actually isn't NULL, you don't need to check if its empty via empty()
Update
You should really test $_POST['id'] if its valid. I'd suggest you to implement a function, like, is_id_valid()
function is_id_valid(&$id){ //<-- IMPORTANT, Argument should be a reference 
  if ( ! isset($id) ){
     return false;
  }
  if ( empty($id) ){
    return false;
  }
  // add this if you expect $id to be a numeric value
  // otherwise just ignore - do not add
  if ( ! is_numeric($id) ){
    return false;  
  }
  //it's also a good to validate the length 
  if ( strlen($id) > ... && strlen($id) < ... ){
     return false;
  } 
  //seems like all tests passed
  return true;
}
Then you would use it, like
if ( is_id_valid($_POST['id']) !== false ){
   ....
}
Warning: It's still vulnerably to SQL injection