SELECT a.*, b.*
FROM a
LEFT OUTER JOIN b
ON b.user IN (:userlist)
AND b.key = a.fk_to_b
WHERE
a.user IN (:userlist)
OR b.user IN (:userlist)
当:userlist参数包含单个值时,数据库仅使用索引。当:用户包含多个值(内部扩展为多个OR语句?)时,不使用索引并执行表扫描(b)。
为什么数据库在提供多个:userlist值时不使用索引?
有谁知道这个查询的更优化版本?
答案 0 :(得分:1)
此查询适用于所有主要系统,可能效率更高:
SELECT a.*, NULL
FROM a
WHERE a.user IN (:userlist)
AND a.fk_to_b NOT IN
(
SELECT key
FROM b
)
UNION ALL
SELECT a.*, b.id
FROM a
JOIN b
ON b.key = a.fk_to_b
WHERE b.user IN (:userlist)
您能告诉我您使用哪个RDBMS
吗?
答案 1 :(得分:0)
快速回答是:这取决于。
如果在:userlist中指定多个值,则数据库服务器可以选择以不同的方式优化查询,例如,它可以选择全表扫描。
大多数情况下,最好的选择是通过执行
来查看查询的优化方式为了帮助您,我们确实需要知道您正在使用哪个数据库。
答案 2 :(得分:0)
IN(:userlist)扩展为多个OR语句 查询优化器忽略OR行/子句 如果数据库是Oracle,那么该怎么做:
CREATE TABLE userListTable
(
sessionId NUMBER(9),
user NUMBER(9)
);
CREATE INDEX userListTableMulti1 ON userListTable(sessionId,user);
...
CREATE OR REPLACE FUNCTION fn_getUserList(parmUserList VARCHAR2)
RETURN NUMBER DETERMINISTIC
varUser NUMBER(9);
varSessionId NUMBER(9);
BEGIN
varSessionId := sys_context('USERENV','SESSIONID');
-- You have to work on a VARCHAR2TOLIST() function
FOR varUser IN VARCHAR2TOLIST(parmUserList) LOOP
INSERT INTO userListTable(sessionId,user)
VALUES(varSessionId, varUser)
END LOOP;
INSERT INTO resultsTable
SELECT
varSessionId as sessionId ,
a.* ,
b.*
FROM
(SELECT a.*
FROM a
INNER JOIN userListTable
ON a.user = userListTable.user AND
userListTable.sessionId = varSessionId) a
LEFT OUTER JOIN (SELECT b.*
FROM b
INNER JOIN userListTable
ON b.user = userListTable.user AND
userListTable.sessionId = varSessionId) b
ON b.key = a.fk_to_b;
RETURN varSessionId;
END;
/
...
// C Client side
int varSessionId;
char* parmUserList;
char* sqlStr;
...
sqlStr = (char*)malloc( strlen(parmUserList) + 17 ) ;
sprintf(sqlStr,"fn_getUserList(%s)", parmUserList);
// EXEC_SQL_FUNC_C_MACRO
// EXEC_SQL_RETURN_QUERY_RESULTS_C_MACRO
// EXEC_SQL_C_MACRO
// are all based on the database API C libraries
// Run the function for this session
varSessionId = EXEC_SQL_FUNC_C_MACRO(sqlStr);
free(sqlStr);
// Get the results
sqlStr = (char*)malloc(128);
sprintf(
sqlStr,
"SELECT * "
"FROM resultsTable "
"WHERE sessionId=%s",
varSessionId);
EXEC_SQL_RETURN_QUERY_RESULTS_C_MACRO(sqlStr);
free(sqlStr);
...
// Clean up the resultsTable for this session
sqlStr = (char*)malloc(128);
sprintf(
sqlStr,
"DELETE "
"FROM resultsTable "
"WHERE sessionId=%s",
varSessionId);
EXEC_SQL_C_MACRO(sqlStr);
free(sqlStr);
// Clean up the userListTable for this session
sqlStr = (char*)malloc(128);
sprintf(
sqlStr,
"DELETE "
"FROM userListTable "
"WHERE sessionId=%s",
varSessionId);
EXEC_SQL_C_MACRO(sqlStr);
free(sqlStr);