tschwarzinger opened a new issue, #24944:
URL: https://github.com/apache/datafusion/issues/24944

   ### Is your feature request related to a problem or challenge?
   
   Currently, DataFusion's Parquet reader (to my understanding) only applies 
pruning/data skipping during  the execution of the `DataSourceExec`. While this 
keeps the effort during planning at a minimum, it also makes it difficult to 
estimate the cardinality of Parquet scans without any external statistics 
information.
   
   So, for example, given the table `movie_info` in the imdb benchmark some 
filters are highly selective. See an example taken from `3b.sql`:
   
   ```text
   > SELECT COUNT(*) FROM movie_info;
   +----------+
   | count(*) |
   +----------+
   | 14835720 |
   +----------+
   1 row(s) fetched.
   Elapsed 0.001 seconds.
   
   > SELECT COUNT(*) FROM movie_info WHERE info  IN ('Bulgaria');
   +----------+
   | count(*) |
   +----------+
   | 2287     |
   +----------+
   1 row(s) fetched.
   Elapsed 0.325 seconds.
   ```
   Unfortunately, pruning doesn't help much here as the file is not sorted on 
the info column (`scan_efficiency_ratio=69.41% (210.9 M/303.8 M)` on the 
Parquet scan). Of course, the ideal scenario is that the rows are clustered on 
the values that the filter predicates on. For example, by sorting the 
`movie_info` table on `info`. I think it's not an uncommon scenario that 
Parquet files are (almost) sorted on particular columns that are regularly used 
for filters. For these scenarios we could get better statistics:
   
   ```text
   > COPY (SELECT * FROM movie_info ORDER BY info) TO 
'./benchmark/data/imdb/movie_info_sorted.parquet' STORED AS parquet;
   +----------+
   | count    |
   +----------+
   | 14835720 |
   +----------+
   1 row(s) fetched.
   Elapsed 8.571 seconds.
   
   > CREATE EXTERNAL TABLE movie_info_sorted STORED AS PARQUET LOCATION 
'./benchmark/data/imdb/movie_info_sorted.parquet';
   > EXPLAIN ANALYZE SELECT COUNT(*) FROM movie_info_sorted WHERE info  IN 
('Bulgaria');
   ```
   
   Now we have: `scan_efficiency_ratio=0.27% (800.7 K/298.2 M)` and 
`page_index_rows_pruned=1.05 M total → 15.36 K`. So, from what I can tell, we 
could put an `Precision::Inexact(15.36K)` as a good estimate of the filter 
selectivity.
   
   If we would have these stats available during planning we (I think) could 
do: i) better join ordering and ii) other optimizations. For example, given the 
`800.7K` scanned bytes in the statistics, it could trigger an eager fetch for 
this scan as it is considered small 
(https://github.com/apache/datafusion/issues/24922). In an object store 
environment this could shave-off about 150ms from the query latency (ignoring 
the effect of better join ordering).
   
   I think there are some possible downsides to consider:
   - planning takes longer
   - there could be a cheap and highly selective dynamic filter (e.g., 
`table_id =  1`)  that would be cheaper and would make the pruning that we 
already did unnecessary.
   - Something I did not consider apart from making configuration even more 
involved?
   
   ### Describe the solution you'd like
   
   Some thing like this:
   
   ```rust
   /// Sets whether the Parquet scanner should do some work during planning to 
get better statistics 
   enum EagerParquetPruning {
       /// No pruning during planning
       Disabled,
       /// Do row group pruning during planning
       RowGroups,
       /// Do row group and page index pruning during planning
       PageIndex,
       /// Do bloom filter pruning during planning.
       BloomFilters,
       /// Do full pruning during planning.
       Full
   }
   ```
   
   Then, during physical planning of the scan, we can do the pruning and update 
the statistics for `FileGroups` etc. Doing that, the remainder of the 
optimization pipeline should see (hopefully) more accurate statistics. 
   
   It's just important that we cannot rely too much on these stats. For scans 
that filter on columns that are clustered together in the Parquet file, this 
can become relatively accurate (e.g., down to the data page size and maybe 
using the column chunk ndv to trim it down further). So it's imaginable that 
the difference between the full file statistics is large (see above) if the 
data is suitable. This could be an interesting knob for tuning DataFusion to 
use cases with suitable data files.
   
   Eager pruning results could be stored in a `ParquetAccessPlan` to try to 
avoid duplicate work. Maybe we can also add some state to make this more 
efficient (e.g., avoid re-evaluating the predicates that already have been 
evaluated).
   
   One option would be to predicate the eager pruning on whether something 
(e.g., page index) is cached and thus no I/O is needed. But the I/O would be 
necessary during the scan eventually so I am not sure whether this is necessary.
   
   ### Describe alternatives you've considered
   
   _No response_
   
   ### Additional context
   
   Related to:
   - https://github.com/apache/datafusion/issues/15885
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to