从多个表查询产品并组合结果的最有效方式?

时间:2019-04-03 00:50:38

标签: sql postgresql

在具有多个制造商的系统中,我基本上有两个核心类别的产品。系统中的当前查询仅用于处理一种产品。

代码如下:

class View extends JPanel {

    private static final String s = "Click a button.";
    private static final int SIZE = 256;
    private Model model;
    private ColorIcon icon = new ColorIcon(SIZE, Color.gray);
    private JLabel label = new JLabel(s, icon, JLabel.CENTER);
    DefaultPieDataset dataset = new DefaultPieDataset();

    public View(Model model) {
        super(new BorderLayout());
        this.model = model;
        label.setVerticalTextPosition(JLabel.BOTTOM);
        label.setHorizontalTextPosition(JLabel.CENTER);
        this.add(label, BorderLayout.CENTER);
        this.add(genButtonPanel(), BorderLayout.SOUTH);
        PiePlot plot = new PiePlot(dataset);
        plot.setSimpleLabels(true);
        JFreeChart chart = new JFreeChart(null, null, plot, false);
        this.add(new ChartPanel(chart) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(SIZE, SIZE);
            }
        }, BorderLayout.WEST);
        model.addObserver(new ModelObserver());
    }
    …    
    private class ModelObserver implements Observer {

        private int pass, fail;

        @Override
        public void update(Observable o, Object arg) {
            if (arg == null) {
                label.setText(s);
                icon.color = Color.gray;
            } else {
                if ((Boolean) arg) {
                    label.setText("Win!");
                    dataset.setValue("Pass", ++pass);
                } else {
                    label.setText("Keep trying.");
                    dataset.setValue("Fail", ++fail);
                }
            }
        }
    }
    …
}

我想要得到的是:添加另一个表的查询,我认为可以通过两种方式完成:

  1. 有效地在一个查询中同时执行两个查询
SELECT DISTINCT c.id
FROM "Config" c
JOIN "FirstProduct" fp ON c.id = fp.widget
JOIN "TheSupplier" ts ON ts.name = fp.manufacturer
LEFT JOIN "ProductOffer" o ON (o.app = ts.app)
WHERE ts.app = ?appId
AND (?mlid IS NULL OR ?mlid = fp.manufacturer)
AND (o.company IS NULL OR o.manufacturer <> fp.manufacturer)
  1. 执行两个单独的查询,然后将它们合并。
SELECT DISTINCT c.id
FROM "Config" c
JOIN "FirstProduct" fp ON c.id = fp.widget fpw
JOIN "SecondProduct" sp ON c.id = sp.widget spw
JOIN "TheSupplier" ts ON ts.name = fp.manufacturer
LEFT JOIN "ProductOffer" o ON (o.app = ts.app)
WHERE ts.app = ?appId
AND (?mlid IS NULL OR ?mlid = fp.manufacturer)
AND (o.company IS NULL OR o.manufacturer <> fp.manufacturer)

这将在生产系统中进行,因此对性能的关注并不重要。

1 个答案:

答案 0 :(得分:0)

这两个查询不相同。根据您的描述,第二个将产生您想要的结果。最后我做了一个小修正:

with
first_product_table as (
  SELECT DISTINCT c.id
  FROM "Config" c
  JOIN "FirstProduct" fp ON c.id = fp.widget
  JOIN "TheSupplier" ts ON ts.name = fp.manufacturer
  LEFT JOIN "ProductOffer" o ON o.app = ts.app
  WHERE ts.app = ?appId
  AND (?mlid IS NULL OR ?mlid = fp.manufacturer)
  AND (o.company IS NULL OR o.manufacturer <> fp.manufacturer)
),
second_product_table as (
  SELECT DISTINCT c.id
  FROM "Config" c
  JOIN "SecondProduct" sp ON c.id = sp.widget spw
  JOIN "TheSupplier" ts ON ts.name = fp.manufacturer
  LEFT JOIN "ProductOffer" o ON (o.app = ts.app)
  WHERE ts.app = ?appId
  AND (?mlid IS NULL OR ?mlid = fp.manufacturer)
  AND (o.company IS NULL OR o.manufacturer <> fp.manufacturer)
)
select * from first_product_table
UNION
select * from second_product_table

如果您担心性能,则需要确保您拥有正确的索引。当指定参数mlid时,以下两个索引是最重要的:

create index ix1 on FirstProduct (manufacturer);
create index ix2 on SecondProduct (manufacturer);

然后,如果查询仍然很慢,则可以尝试:

create index ix3 on TheSupplier (name, app);
create index ix4 on ProductOffer (app, company, manufacturer);

最终说明:请考虑以下条件o.manufacturer <> fp.manufacturer可能会过滤掉您想要的行,因为它有效地否定了外部联接,将其转换为内部联接。也许您希望每个部分的最后四行如下所示:

  LEFT JOIN "ProductOffer" o ON (o.app = ts.app)
    AND (o.company IS NULL OR o.manufacturer <> fp.manufacturer)
  WHERE ts.app = ?appId
  AND (?mlid IS NULL OR ?mlid = fp.manufacturer)

但这只是一个猜测,因为我不完全了解您的要求。