ホームページ  >  記事  >  バックエンド開発  >  MySQL データベースのクエリ効率を向上させるためのいくつかのヒント [PHP プログラマー必読]_PHP チュートリアル

MySQL データベースのクエリ効率を向上させるためのいくつかのヒント [PHP プログラマー必読]_PHP チュートリアル

WBOY
WBOYオリジナル
2016-07-20 11:05:22815ブラウズ

MySQL は、そのコンパクトさと効率的な操作により、データベース アプリケーションで使用されることが増えています。私が P2P アプリケーションを開発していたとき、P2P アプリケーションではノードの数が数万に達する可能性がありました。ノードは頻繁に変更されるため、クエリと挿入を効率的に保つ必要があります。使用中の効率を向上させるために私が行った 3 つの効果的な試みです。

l
バインドされたクエリにステートメントを使用する
クエリ構文ツリーを構築します。クエリを実行する前に構文ツリーを構築する必要がなくなり、クエリの条件は固定されているものの、クエリの頻度が非常に高い場合にこの方法が適しています。

Bind 定義し、MYSQL_STMT 変数を作成し、対応するクエリ文字列にバインドします。文字列内の疑問符は、渡される変数を表します。各疑問符は、

Query で指定された変数をそれぞれ指定する必要があります。 MYSQL_STMT 使用可能な接続句柄実行を渡します。
代码如下:

//1.绑定

bool CDBManager::BindInsertStmt(MYSQL * connecthandle)
{
//作入操作の決定
MYSQL_BI ND インサートバインド[FEILD_NUM] ];
if(m_stInsertParam == NULL)
m_stInsertParam = new CHostCacheTable;
m_stInsertStmt = mysql_stmt_init(connecthandle)
strcpy(insertSQL) , "insert into HostCache(SessionID, ChannelID, ISPType, "
"外部IP、外部ポート、内部IP、内部ポート) "
"values(?, ?, ?, ?, ?, ?, ?)");
"mysql_stmt_prepare(m_stInsertStmt, insertSQL, strlen(insertSQL ));
int param_count= mysql_stmt_param_count(m_stInsertStmt);
‑ の' 's ' s ' ‑ ' ‑ ‐ ‐‐‐ and � (insertbind, 0, sizeof(insertbind));
insertbind [0].buffer_type = MYSQL_TYPE_STRING;
insertbind[0].buffer_length = ID_LENGTH /* -1 * /;
insertbind[0].buffer = (char *)m_stInsertParam->sessionid;
insertbind[0].is_null = 0; n insertBind [0] .Length = 0;

insertBind [1] .buffer_type_string ;
insertBind [1] .buffer_length = id_length / * -1 * /; d [1] .buffer = (char * )m_stInsertParam->channelid;
insertbind[1].is_null = 0;
insertbind[1]。 length = 0;

insertbind[2].buffer_type = MYSQL_TYPE_TINY;

insertbind[2].buffer = (char * ) &m_stInsertParam->ISPtype;

insertbind[2].is_null = 0;
insertbind[2].length = 0;

insertbind[3].buffer_type = MYSQL_TYPE_LONG;
insertbind[3].buffer = (char *)&m_stInsertParam ->externalIP;

insertbind[3].is_null = 0;

insertbind[3].length = 0;


insertbind[4].buffer_type = MYSQL_TYPE_SHORT;

insertbind[4].buffer = (char *)&m _stInsertParam ->externalPort;

insertbind[4].is_null = 0;
insertbind[4].length = 0;

insertbind[5].buffer_type = MYSQL_TYPE_LONG;

insertbind[5].buffer = (char *)&m_stInsert Param- >internalIP;

insertbind[5].is_null = 0;
insertbind[5].length = 0;

insertbind[6].buffer_type = MYSQL_TYPE_SHORT;
insertbind[6].buffer = (char *)&m_stInsertParam->internalPort;
insertbind[6].is_null = 0;
insertbind[6].is_null = 0;
/ /绑定
if (mysql_stmt_bind_param(m_stInsertStmt, insertbind))
return false;
return true;
}

//2.查询
bool CDBManager::InsertHostCache2 (MYSQL * 接続ハンドル、char * セッション ID、char * チャネル ID、int ISPtype,
unsigned int eIP, unsigned short eport, unsigned int iIP, unsigned short iport)
{
//充填结构变量m_sInsertParam
strcpy(m_stInsertParam->sessionid, sessionid);
strcpy(m_stInsertParam->チャンネルid, チャンネルid );
m_stInsertParam->ISPtype = ISPtype;
m_stInsertParam->externalIP = eIP;
m_stInsertParam->externalPort = eport;
m_stInsertParam-> innerIP = iIP;
m_stInsertParam->internalPort = iport;
//実行ステートメント、性能瓶颈处
if(mysql_stmt_execute(m_stInsertStmt))
return false;
return true;
}

l
随机の获取记录
库の使用中、私はすべての十分な条件を取得する必要はありませんの记录ではなく、単に机に挑戦して十分な条件を選択する必要があるだけです。 このような状況は、大容量データ プールから少量のデータを取得するデータ トラフィックの分析でよく見られます。       通常の方法では、最初にすべての十分な条件の評価が出力され、その後、徐々に挑戦的な部分が抽出されます。この方法は、十分な条件の評価数では多くの場合、効果が期待できません。       制限法を使用して、最初に十分な条件の承認数を取得し、その後、SQL の承認の句にlimit を追加して、要求を満たすだけの承認を制限します。 このような方法は 2 回確認する必要がありますが、データ量の面ではより高い効果があります。結果収集 500ms、残り可忽略

int CDBManager::QueryHostCache(MYSQL* connecthandle, char * channelid, int ISPtype, CDBManager::CHostCacheTable * &hostcache)

{

char selectSQL[SQL_LENGTH];
memset(selectSQL, 0, sizeof(selectSQL));
sprintf(selectSQL,"select * from HostCache where ChannelID = '%s' and ISPtype = %d", channelid, ISPtype);
if(mysql_real_query(connecthandle、selectsql、strlen(selectsql))
; [1]!= null)
(M_ROW [2]!= null)s's 's' s 's' s 's' s sを通して' s ' を通じて ' s ' を通じて ‐ to ‐ ‐ ‐ww hostcache.externalIP = atoi(m_Row[3]) [4] , hostcache.internalIP = atoi(m_Row[5]);
] != NULL)
hostcache. {
// 指定されたレコードをランダムに選択して返します
              int iRemainder = iAllNumRows%iReturnNumRows;    /// int iQuotient = iAllNumRows/iReturnNumRows;      ///<商
int iStartIndex = rand()%(iRemainder + 1);         ///<开始下标

//获取逐条记录
for(int iSelectedIndex = 0; iSelectedIndex < iReturnNumRows; iSelectedIndex++)
{
{
mysql_data_seek(m_pResultSet, iStartIndex + iQuotient * iSelectedIndex);
m_Row = mysql_fetch_row(m_pResultSet );
if(m_Row[0] != NULL)
strcpy(hostcache[iSelectedIndex].sessionid, m_Row[0]);
if(m_Row [1] != NULL)
strcpy(hostcache[iSelectedIndex].channelid, m_Row[1]);
if(m_Row[2] != NULL)
hostcache[iSelectedIndex].ISPtype atoi(m_Row[2]);
if(m_Row[3] != NULL)
hostcache[iSelectedIndex]。 externalIP = atoi(m_Row[3]);
if(m_Row[4] != NULL)
hostcache[iSelectedIndex].externalPort = atoi(m_Row[4]);
if(m_Row[5] != NULL)
ホストキャッシュ[iSelectedIndex].internalIP = atoi(m_Row[5]);
if(m_Row[6] != NULL)
hostcache[iSelectedIndex].internalPort = atoi(m_Row[6]);
}
}
//释放结果要約内容
mysql_free_result(m_pResultSet);
return iReturnNumRows;

}


//2.uselimit版
int CDBManager::QueryHostCache(MYSQL * connecthandle, char * channelid, unsigned int myexternalip, int ISPtype,可能な * ホストキャッシュ)
{
//首先获取满十分結果の记录条数、再使用制限随机选择指定条记录返
MYSQL_ROW row;
MYSQL_RES * pResultSet;
char selectSQL[SQL_LENGTH];

memset(selectSQL, 0, sizeof(selectSQL)) ;🎜

sprintf(selectSQL,"select count(*) from HostCache where ChannelID = '%s' and ISPtype = %d", channelid, ISPtype);
if(mysql_real_query(connecthandle, selectSQL, strlen(selectSQL)) != 0) //検索
return 0;
pResultSet = mysql_store_result(connecthandle);
if(!pResultSet)
return 0;
row = mysql_fetch_row( pResultSet);
int iAllNumRows = atoi(row[0]);
mysql_free_result(pResultSet) ;
//计算待ち取记录の上下范围
int iLimitLower = (iAllNumRows <= RETURN_QUERY_HOST_NUM)?
0:(rand()%(iAllNumRows - RETURN_QUERY_HOST_) NUM));
int iLimitUpper = (iAllNumRows <= RETURN_QUERY_HOST_NUM)?
iAllNumRows:(iLimitLower + RETURN_QUERY_HOST_NUM);
//返される計算結果数
int iReturnNumRows = (iAllNumRows <= RETURN_QUERY_HOST_NUM)?
iAllNumRows:RETURN_QUERY_HOST_NUM;


//使用制限作查询
sprintf(selectSQL," select SessionID, ExternalIP, ExternalPort, InternalIP, InternalPort "
"from HostCache where ChannelID = '%s' and ISPtype = %d limit %d, %d"
, channelid, ISPtype, iLimitLower, iLimitUpper);
if(mysql_real) _クエリ( connecthandle, selectSQL, strlen(selectSQL)) != 0) //检索
return 0;
pResultSet = mysql_store_result(connecthandle);
if(!pResultSet)
return 0;
//获取逐条记录
for(int i = 0; i {
//获取逐語句
row = mysql_fetch_row(pResultSet);
if(row[0] != NULL)
strcpy(hostcache.sessionid, row[0]);
if(row[1] ! = NULL)
hostcache.externalIP = atoi(row[1]);
if(row[2] != NULL)
hostcache.externalPort = atoi(row[2]);
if(row[3] != NULL )
hostcache.internalIP = atoi(row[3]);
if(row[4] != NULL)
hostcache.internalPort = atoi(row[4]);            
}
//释放结果集内容
mysql_free_result(pResultSet);
return iReturnNumRows;
}

l
接続を管理するには接続プールを使用します。
多数のノードがアクセスされるデータベース設計では、すべての接続を管理するために接続プールがよく使用されます。
一般的な方法は、2 つの接続ハンドル キューと、接続を待機するアイドル キューを確立することです。
クエリを実行するときは、まず空きキューからハンドルを取得し、それを使用中のキューに挿入し、完了後にこのハンドルを使用してデータベース操作を実行します。
設計コードは次のとおりです:

//ハンドルキューを定義します
typedef std::list>
typedef std::list: :iterator connection_handle_list_it; // 通常は 0

};

// 2 つのキューを作成します

CONNECTION_HANDLE_LIST m_lsBusyList
;

//すべての接続ハンドルは最初にデータベースに接続され、アイドルキューに追加され、使用されるのを待ちます。
bool CDBManager::Connect(char * host /* = "localhost" */, char * user /* = "チェンミン」 * /、
lpDBParam->host = ホスト;
lpDBParam ->user = ユーザー;
lpDBParam->password = パスワード;
lpDBParam->データベース = データベース;
lpDBParam->ポート = 0;
lpDBParam->unix_socket = NULL;
lpDBParam->client_flag = 0;
try
MYSQL * pConnectHandle = mysql_init((MYSQL*) 0) //接続ハンドルを初期化します
if(! mysql_real_connect(pConnectHandle, lpDBParam- >ホスト、lpDBParam->ユーザー、lpDBParam->パスワード、
lpDBParam->データベース、lpDBParam->ポート、lpDBParam->unix_socket、lpDBParam->client_fla))
return false;
//Addアイドルキューに
false を返す;

MYSQL * 用のハンドルger::GetIdleConnectHandle()
{
MYSQL * pConnectHandle = NULL;
m_ListMutex.acquire();
pConnectHandle = m_lsIdleList.front();
m_lsIdleList 。 Pop_front();
m_lsBusyList.push_back(pConnectHandle); }
m_ListMutex.release();

pConnectHandle;
}
// 使用するハンドルを使用キューから解放し、空きキューに挿入します。

Void CDBMANAGER :: SetidLeConnecthandle (MySQL * Connecthandle) {
m_lsbusylist. Remove (connecthandle); (connecthandle);
m_ListMutex.release();
}
//使用例、最初にアイドル ハンドルを取得し、このハンドルを使用して実際の操作を実行し、それからアイドル キューに戻します
bool CDBManager::DeleteHostCacheBySessionID(char) * sessionid)
{
MYSQL * pConnectHandle = GetIdleConnectHandle();
if(!pConnectHandle)
return 0;
bool bRet = DeleteHostCacheBySessionID(pConnectHandle, sessionid);
SetIdle ConnectHandle(pConnectHandle);
bRet ;
}
/ /Incoming idle 実際の削除操作を実行するハンドル
bool CDBManager::DeleteHostCacheBySessionID(MYSQL * connecthandle, char * sessionid)
{
char deleteSQL[SQL_LENGTH];
memset(deleteSQL, 0, sizeof(deleteSQL));
sprintf (deletesql、「hostcacheからdelete where where sessionid = '%s'」、sessionid);




http://www.bkjia.com/PHPjc/445134.html

www.bkjia.com

tru​​e
http://www.bkjia.com/PHPjc/445134.html

技術記事 MySQL は、そのコンパクトさと効率的な操作により、データベース アプリケーションで使用されることが多くなりました。私が P2P アプリケーションを開発していたとき、P2P のアプリケーションのため、MySQL を使用していました。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。