This is an automated email from the ASF dual-hosted git repository.
dengzhhu653 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git
The following commit(s) were added to refs/heads/master by this push:
new d0050d9e85a HIVE-30153: Avoid unnecessary SERDES join in
PartitionProjectionEvaluator when no serde field is projected (#6864)
d0050d9e85a is described below
commit d0050d9e85a628767e97f02ebceaae6ddea775e2
Author: Yuming Wang <[email protected]>
AuthorDate: Tue Oct 13 07:43:06 2026 +0800
HIVE-30153: Avoid unnecessary SERDES join in PartitionProjectionEvaluator
when no serde field is projected (#6864)
---
.../metastore/PartitionProjectionEvaluator.java | 4 +-
.../TestPartitionProjectionEvaluator.java | 54 ++++++++++++++++++++++
2 files changed, 55 insertions(+), 3 deletions(-)
diff --git
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PartitionProjectionEvaluator.java
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PartitionProjectionEvaluator.java
index 6841380b24a..b249204ab58 100644
---
a/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PartitionProjectionEvaluator.java
+++
b/standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PartitionProjectionEvaluator.java
@@ -522,15 +522,13 @@ private int buildQueryForSingleValuedFields(List<Long>
partitionIds, StringBuild
queryTextBuilder.append(SPACE);
queryTextBuilder.append("from " + PARTITIONS);
// if SD fields are selected add join clause with SDS
- boolean foundSD = false;
if (find(SD_PATTERN)) {
queryTextBuilder.append(SPACE);
queryTextBuilder.append(
"left outer join " + SDS + " on " + PARTITIONS + ".\"SD_ID\" = " +
SDS + ".\"SD_ID\"");
- foundSD = true;
}
// if serde fields are selected add join clause on serdes
- if (foundSD || find(SERDE_PATTERN)) {
+ if (find(SERDE_PATTERN)) {
queryTextBuilder.append(SPACE);
queryTextBuilder.append(
" left outer join " + SERDES + " on " + SDS + ".\"SERDE_ID\" = " +
SERDES
diff --git
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/TestPartitionProjectionEvaluator.java
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/TestPartitionProjectionEvaluator.java
index c40a67b9678..44cea15890a 100644
---
a/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/TestPartitionProjectionEvaluator.java
+++
b/standalone-metastore/metastore-server/src/test/java/org/apache/hadoop/hive/metastore/TestPartitionProjectionEvaluator.java
@@ -26,11 +26,14 @@
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import javax.jdo.PersistenceManager;
+import javax.jdo.Query;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -239,6 +242,57 @@ public void testFind() throws MetaException {
Assert.assertTrue(projectionEvaluator.find(CD_PATTERN));
}
+ /**
+ * Captures the SQL text that the evaluator hands to the PersistenceManager
while answering
+ * {@link
PartitionProjectionEvaluator#getPartitionsUsingProjectionList(List)}, without
reaching
+ * into any private method. The PersistenceManager/Query are mocked just
like in the rest of this
+ * test class; the mocked query simply returns no rows so the evaluator
exits its result loop
+ * immediately after the SQL has been built and submitted.
+ */
+ private String captureGeneratedQuery(PersistenceManager mockPm,
+ List<String> projectionFields) throws Exception {
+ Query mockQuery = Mockito.mock(Query.class);
+ Mockito.when(mockPm.newQuery(Mockito.anyString(),
Mockito.any())).thenReturn(mockQuery);
+ Mockito.when(mockQuery.execute()).thenReturn(Collections.emptyList());
+
+ PartitionProjectionEvaluator projectionEvaluator =
+ new PartitionProjectionEvaluator(mockPm, fieldNameToColumnName,
projectionFields, false,
+ false, null, null);
+ Deadline.registerIfNot(100_000);
+ Deadline.startTimer("getPartitionsUsingProjectionList");
+ try {
+
projectionEvaluator.getPartitionsUsingProjectionList(Collections.singletonList(1L));
+ } finally {
+ Deadline.stopTimer();
+ }
+
+ ArgumentCaptor<String> sqlCaptor = ArgumentCaptor.forClass(String.class);
+ Mockito.verify(mockPm).newQuery(Mockito.eq("javax.jdo.query.SQL"),
sqlCaptor.capture());
+ return sqlCaptor.getValue();
+ }
+
+ @Test
+ public void testSerdesNotJoinedWhenOnlySdFieldsRequested() throws Exception {
+ String generatedSql =
captureGeneratedQuery(Mockito.mock(PersistenceManager.class),
+ Arrays.asList("createTime", "sd.location"));
+
+ Assert.assertTrue("sd field is requested, SDS should be joined",
+ generatedSql.contains("join " + "\"SDS\""));
+ Assert.assertFalse("no serde field is requested, SERDES should not be
joined",
+ generatedSql.contains("\"SERDES\""));
+ }
+
+ @Test
+ public void testSerdesJoinedWhenSerdeFieldRequested() throws Exception {
+ String generatedSql =
captureGeneratedQuery(Mockito.mock(PersistenceManager.class),
+ Arrays.asList("createTime", "sd.serdeInfo.serializationLib"));
+
+ Assert.assertTrue("sd field is implied by a serde field, SDS should be
joined",
+ generatedSql.contains("join " + "\"SDS\""));
+ Assert.assertTrue("serde field is requested, SERDES should be joined",
+ generatedSql.contains("join " + "\"SERDES\""));
+ }
+
@Test(expected = MetaException.class)
public void testFindNegative() throws MetaException {
PersistenceManager mockPm = Mockito.mock(PersistenceManager.class);